Page 1 of 2

Programmer en hexa directement, c'est possible !

Unread postPosted: 10 Dec 2011, 14:18
by matref
¡ Hola la gente !

J'ai demandé il y a un peu de temps s'il existait un tutoriel d'hexadécimal, pour pouvoir programmer on-calc en autre chose qu'en Ti-basic. On m'a dit que ça ne devait pas exister, vu la complexité du truc. Alors comme je suis maso ( :D: ) j'ai décidé d'apprendre l'hexa tout seul (et là j'ai compris pourquoi y'a pas de tutos :o: ).

Toujours est-il que si vous voulez programmer on-calc, que vous ne comptez pas vous relire un jour et que vous aimez les challenges, vous pouvez programmer en hexadécimal . :D

Donc ben je me suis dit "tiens ben je m'en sors pas trop mal, j'ai qu'à en faire profiter les gens ça leur évitera de souffrir inutilement. Alors ben voilà, je vous dit ce que je sais et j'édite au fur et à mesure :)

Ah oui aussi : ce dont je vais parler ici c'est de l'hexadécimal pour Ti-83+, 83+ SE, 84+ et 84+ SE. N'essayez pas de suivre avec une autre calto, tout ce que vous allez faire c'est la ruiner un maximum.
De plus, je pars du fait que vous "avez déjà entendu parler de l'ASM". Donc faut savoir ce qu'est une romcall et un registre en gros.



Pour voir la suite du post et tout le tutorial, cliquez sur ce topic !

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 10 Dec 2011, 16:09
by matref
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écimal

Pour créer un programme hexa sur une des calculatrices ci-dessus (les autres fichez le camp :D ), 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écimal

Si 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 :lol: 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écimal

L'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 :P

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 :P ), 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 !!! :D

Les registres et l'assignation en hexadécimal

Aï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 !!!!! :ok:

Commençons avec les registres. Ben c'est les mêmes qu'en ASM c'est juste qu'ils s'appellent pas pareil :lol:

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 registre

C'est le cas le plus courant, qui correspond à assigner une valeur hexadécimale (on fait de l'hexa je rappelle :D ) à 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 :lol:
  • 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 :lol: je m'en suis juste rendu compte lors de mes tests.

L'assignation registre vers registre

Accrochez-vous, là ça devient vraiment compliqué.

Les registres 8 bits

Pour 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 :P , 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 :D : 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 ? :D 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 :
  • D à H
  • C à A
  • L à B
  • A à L
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 ...
:shock:
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 bits

Avec les registres 16 bits, c'est très simple : on fait pas :P . 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 romcalls

Là 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 :P

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 :P

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 !

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 10 Dec 2011, 17:44
by Lionel Debroux
Dans l'absolu, c'est une bonne idée de séparer le post introductif et le contenu (par exemple, pour rendre plus visible l'historique des mises à jour) - mais persalteas ne va pas pouvoir éditer le message d'Adriweb ;)

Une solution est que persalteas reposte le contenu de l'actuel post d'Adriweb, puis qu'on efface le post d'Adriweb et le mien :)

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 10 Dec 2011, 18:34
by Claros
Lionel Debroux wrote:Une solution est que persalteas reposte le contenu de l'actuel post d'Adriweb, puis qu'on efface le post d'Adriweb et le mien :)

Plus simple : un modérateur change l'auteur du message.

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 10 Dec 2011, 18:40
by Excale
Claros wrote:Plus simple : un modérateur change l'auteur du message.


La dernière fois que l'on a fait ça il y a eu quelques effets secondaires si j'ai bonne mémoire :D.

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 10 Dec 2011, 21:21
by M@yeulC
Whaou : ça, c'est du bas niveau :#fou#:

Mais ça me tente bien : je crois que je vais me mettre à l'asm rien que pour ça (après la prépa)

J'espère que d'ici là le tutoriel sera un peu plus complet.

Mais c'est du bon boulot, vraiment!

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 11 Dec 2011, 03:18
by matref
Salut les gens ! C'est moi l'éditeur du tuto !

J'ai regardé un peu le site après que Persalteas m'ait demandé les droits, pour voir un peu où mon tuto allait atterrir, ça m'a bien plu donc hop me voilà ^^

Sinon, Persalteas : gros update sur les registres, ajout d'une sous partie sur la syntaxe dans "Structurer son code hexa" et ajout d'un p'tit exo à la fin. Tu fais comment, tu update le post ? J'ai déjà updaté sur Espace-ti.

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 11 Dec 2011, 08:32
by Lionel Debroux
Bienvenue sur TI-Planet :)

On va modifier le deuxième post, d'une façon ou d'une autre.

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 11 Dec 2011, 10:19
by Persalteas
Arf, zut... effectivement, je peux pas éditer les posts d'Adriweb... :#roll#:

En attendant, ceux qui veulent suivre le tuto AVEC LES MISES A JOUR, rendez vous ici:

http://espace-ti.forumactif.com/t576-pr ... ible#10476

Re: Programmer en hexa directement, c'est possible !

Unread postPosted: 11 Dec 2011, 20:33
by matref
Grosse mise à jour, chapitre sur les registres et l'assignation enfin complet :)