__ _____________ / \ / ___________ \ /\ /\ \ / / / / \ / \ / \ / \ / / \__/ / \ / \ / /\ \ \ \_____________ / /\ \ / /\ \ / \/ \ \_____________ \ / / \ \/ / \ \ __ / /\__/\ \ __ \ \ / / \ / \ \ / \/ / \ \/ \ /\ \ \ / / / \ \ \ \ / \ / / / / / / \ \ / / \ \__/ \__/ / \________/ / \___/ \ / \___/ \____________/ \/ L'assembleur débutant ~~~~~~~~~~~~~~~~~~~~~ Cette série d'articles a pour but d'enseigner les joies de l'assembleur aux personnes non initiées à cet étrange pratique. Je conseille vivement aux étourdis qui commencent l'apprentissage de lire le premier cours qui est une introduction générale et nécessaire à la compréhension de ce qui suit. Ce second cours introduit les instructions les plus utilisées en assembleur, ou plus particulièrement celles utilisées par les algorithmes des démos. Je vous recommande vivement d'usiter d'un assembleur et de tester les instructions que nous verrons ensemble. On ne peut pas apprendre l'assembleur si on ne voit pas bien concrètement les choses. Pour ma part, j'utilise Asm-one et toutes les instructions concernant l'assembleur-debuggeur seront pour ce logiciel. Il est facile à trouver puisque la majorité des démos makers l'utilise. Le cours est illustré d'un bon nombre d'exemples simples alors testez les! Vous ne trouverez pas dans ce cours une liste de TOUTES les instructions existantes en 68000 car ça sert à rien et ça traîne dans n'importe quel bouquin traitant du sujet. Mais ne vous inquiétez pas, la majeure parties des instructions utiles sont explicitées ici. En fait, j'ais repris les instructions qui m'ont servis à faire ma dernière routine ( Gestion d'un monde 3d à 3degrés de liberté en 4Millions de couleurs ). Donc je pense que vous arriverez à vous en sortir avec. ~~~~~~~~~ Cours n°2 ~~~~~~~~~ Les Instructions ~~~~~~~~~~~~~~~~ Si vous désirez dès a présent charger Asm-one, ce qui est une excellente initiative, faites comme suit: ALLOCATE Chip/Fast/.....>C ( 'C' comme Chip. ) WORKSPACE > 50 ( '50' Kb pour stocker la source.) Et on y va ... I.1 Instructions : MOVE , ADD , SUB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ On commence tout de suite par un exemple: ;----------------------Programme 1------------------------------------ Start: Move #24,D0 ; Met la valeur 24 dans D0. Add #10,D0 ; Ajoute 10 à D0. Sub #4,D0 ; Retranche 4 à D0. Move D0,result ; Met la valeur de D0 à l'adresse 'Result' Clr D0 ; Efface D0 Rts ; Fin du programme Result: Dc.w $0000 ; Reserve un mot. ;--------------------------------------------------------------------- (avant les instructions, il faut mettre une tabulation !! ) Pour saisir le programme, appuyez sur 'esc' et vous rentrerez sous l'éditeur. Tapez le programme en respectant bien les tabulations avant les instructions. Les ';' indiquent le début d'un commentaire. (alors ne les recopiez pas!). Lorsque vous avez terminé de taper le programme, appuyez de nouveau sur 'esc' pour sortir de l'éditeur. Un '>' vous indique qu'Asm-one attend une commande. Tapez 'a' (puis 'return' bien sûr) pour assembler la source. Si le message 'no errors' apparaît alors tout va bien pour vous, vous pouvez aller directement au paragraphe suivant. Sinon, il va falloir debugger...et oui déjà. Votre programme comporte des erreurs, il vous faut regarder à nouveau la source. (vérifiez les tabulations en début de ligne, faites attention d'écrire D0 et pas DO, vérifiez la syntaxe). Les commentaires de ce programme expliquent clairement ce qu'il fait. Voici quelques compléments : * D0 est un registre interne du processeur. Il en existe huit du même type ( D0 D1 D2 D3 D4 D5 D6 D7 ). Cette case n'a pas d'adresse et lorsque on veut l'utiliser on utilise le nom D0 tout simplement. * L'instruction 'Move' est ma plus simple des instructions. C'est une affectation. Le '#' signifie que l'on met une valeur directement dans la destination. La destination est ici la case D0. Syntaxe : Move #Valeure,Registre * L'instruction 'Add' sert à ajouter(!). Syntaxe : Add #Valeur,Registre Il en est de même pour l'instruction 'Sub'. Syntaxe : Sub #Valeur,Registre Donc à ce stade du programme, si on suit les trois premières instructions: Move #24,D0 ; 1 Add #10,D0 ; 2 Sub #4,D0 ; 3 1, on met 24 dans D0 (D0=24)... 2, on ajoute 10 à D0 (D0=34) 3,on enlève 4 à D0 (D0=30)... C'est simple mais on a déjà vu trois instructions élémentaires. On continue : * 'Move D0,result'. Voici encore notre instruction Move mais sous une autre forme : Syntaxe : Move Registre,Adresse Ici, on oublie le # car il ne s'agit plus d'une valeur directe mais de la valeur contenue dans la case D0. On sait que cette valeur est 30. Donc 30 va être mis dans la case mémoire qui a pour adresse 'Result'. 'Result' est ce que l'on appelle un label. Un label est une étiquette que l'on pose sur une adresse bien précise. Donc au lieu d'appeler l'adresse $9A096 par exemple, on appellera l'adresse 'Result'. * 'Clr' signifie 'Clear'. Cela se passe de commentaire. Syntaxe : Clr Registre * 'Rts' signifie 'ReTurn from Subroutine'. Dans notre cas il montre la fin du programme. Syntaxe : Rts * 'Dc.w' sert à assembler des datas directement en mémoire. Syntaxe : Dc.w valeur,valeur,valeur,valeur,valeur..etc... Ici 'Dc.w 0' assemble un 0. Donc si on désassemble la mémoire à partir de l'adresse 'Result', on trouvera une case qui avant l'exécution est à $0000 et après exécution sera à 30 ($001e). On peut visualiser directement les cases mémoire avec la commande 'H result'. Essayez avant et après exécution du programme1. ?? 'Dc' signifie 'Data Code'. La notation '.w' signifie que les valeurs assemblées sont au format 'Word'. On distinguera ainsi 3 types de format de données: Byte (Octets) : $00 extension '.b' (Valeurs allant de 0 à 255) Word (Mots) : $0000 extension '.w' (Valeurs allant de 0 à 65535) Long (Long) : $00000000 extension '.l' (Valeurs allant de 0 à bcp!) Ces extensions s'appliquent sur la majeure partie des instructions, par exemple : Move.b #$10,d0 Move.w #$0666,d0 Move.l #$00109700,d0 Add.l #$45687987,d2 Sub.b #$69,d0 I. Instructions : BSR , BRA , JSR , JMP (Sauts) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tout de suite un petit programme : ;-----------------------Programme 2----------------------------------- Start: Bla1 Bsr Efface_Ecran ; Saute a la sous routine Bla3 Jsr Affiche_Caractere ; Saute à la sous routine Bra Fin Bla5 Bla5 Fin Rts ;---------------- ; Sous routines - ;---------------- Efface_Ecran: Bla2 ; Instructions quelconques Bla2 Bla2 Rts ; Fin de la sous routine ;---------------- Affiche_Caractere: Bla4 Bla4 Bla4 Rts ;-------------------------------------------------------------------- Voici la structure possible d'un programme utilisant des appels de sous routines. Pour comprendre, il faut suivre linéairement le déroulement du programme depuis le début. On commence a 'Start' puis le proc exécuté les premières instructions 'Bla1' avant de tomber sur 'Bsr Efface_Ecran' * 'Bsr' ou 'Jsr' Cette instruction est égale au 'Gosub' du basic. Le programme saute à une adresse mémoire pour exécuter un morceau de programme mais il garde souvenir de l'endroit d'où il est parti. Lorsque dans la sous routine appelée, le proc trouve un 'Rts' (ReTurn From Subroutine) il arrête d'effectuer la sous routine et revient à l'endroit où elle avait été appellée et continue le programme. Syntaxe : Bsr Adresse Syntaxe : Jsr Adresse 'Bsr' est une instruction codée en relatif alors que 'Jsr' est codée en absolu. Du point de vue du programmeur leur fonctionnement est identique. Un 'Bsr' ne pourra pas sauter à des sous routines trop lointaine en mémoire alors qu'un 'Jmp' pourra. Si vous avez bien compris, suivez le programme dans l'ordre. Vous devriez voir les 'Bla' dans l'ordre. * 'Bra' C'est un saut sans retour. L'équivalent Basic est 'Goto'. Idem pour 'Jmp' Syntaxe : Bra Adresse Syntaxe : Jmp Adresse Donc dans notre exemple les instructions 'Bla5' ne sont pas executées. I Instructions : DBRA (Utile pour les boucles) ~~~~~~~~~~~~~~~~~~~~~ Essayez le programme suivant : ;----------------------Programme 3----------------------------------- Start: Clr.l d1 Clr.l d2 Move.w #100,d0 Boucle: ; Debut de la boucle Add.w #1,d1 Add.w #2,d2 Dbra d0,Boucle ; Fin de la boucle Rts ; Fin du programme ;-------------------------------------------------------------------- * 'Dbra' Syntaxe : DBra Registre,Adresse Cette instruction utilise un registre (ici D0) qu'elle décrémente à chaque tour de boucle et tant que ce registre ,n'est pas égal à -1, il saute à une adresse. On peut remarquer ici en exécutant le programme que le résultat dans d1 est $65 (=101). Donc attention, cette instruction réalise un tour de boucle supplémentaire. Le programme,pour ceux qui auraient l'esprit ailleurs,réalise 101 fois l'opération d1=d1+1 et d2=d2+2. On peut pour bien être sûr de ce qui se passe utiliser le traceur d'Asm-one. Pour cela choisissez la commande 'Debugger' dans le menu 'Assembler'. On peut suivre ainsi sur la droite de l'écran l'évolution des registres. Pour exécuter une ligne de programme utilisez la flèche curseur vers le bas. Ici l'exemple est simple mais pour des algos plus compliqués très calculatoires, l'utilisation du 'Debugger' est importante. I Instructions : AND , OR , EOR , NOT (Operations Logiques) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Le langage machine est intimement lié avec la notion de logique. La logique booléenne pour ceux qui n'auraient jamais entendu parler de cette science étrange est une façon de réfléchir avec des 1 et des 0. Donc pour un ordinateur qui ne comprend que les 1 et les 0, cela semble le meilleur moyen d'effectuer des opérations simples. N'oubliez jamais que l'ordinateur compte en binaire. Le décimal et l'hexadécimal ne sont que des représentations, à l'intérieur il n'y a que des 0 et des 1 partout. (Ce texte par exemple est constitué de 0 et de 1 uniquement). Voici donc les opérations logiques élémentaires: NOT : C'est la négation. Comme on a que deux états possibles (0 et 1) ~~~ le resultat est instinctif : (NOT 0) = 1 (NOT 1) = 0 AND : C'est le 'et' logique. ~~~ Voici sa table de vérité: \ 0 | 1 | <- Première composante. --|-------| 0 | 0 | 0 | --|-------| <- Les 4 cases de ce tableau représentent. 1 | 0 | 1 | le résultat. ----------- | Seconde composante. Ce tableau résume en fait les 4 possibilités : (0 AND 0) = 0 (0 AND 1) = 0 (1 AND 0) = 0 (1 AND 1) = 1 Vous remarquez que la seule façon d'avoir 1 en sortie d'une opération 'Et' est d'avoir toutes les entrées à 1. EXEMPLE: ~~~~~~~~ Cette opération peut être faite sur plusieurs bits en même temps : 0010100101010000 AND 0110011101110000 = ? Pour effectuer cette opération, il est préférable de placer les composantes l'une en dessus de l'autre : 0010100101010000 AND 0110011101110000 = 0010000101010000. <-résultat Il suffit de regarder les colonnes et d'effectuer l'opération 'And' bit par bit. Lorsque je parlais de représentation, ici nous avons un très bon exemple. Si vous désassemblez la mémoire, vous ne verrez jamais les nombres représentés en binaire comme ci-dessus. En effet cette représentation est trop encombrante. (Voir Cours n°1) Vous verriez : $2950 AND $6770 = $2150 Ce qui est strictement la même chose mais plus pratique à manipuler. EXEMPLE ~~~~~~~ La commande assembleur correspondante est AND. (Eh logique non ?) Elle ne peut se faire que sur les registres de données (d0 d1 d2 d3 d4 d5 d6 d7) Syntaxe : AND #Valeur,Dx Syntaxe : AND Dx,Dx ;----------------------Programme 4------------------------------------ Start: Move.l #$2950,D0 And.l #$6770,D0 Rts ; Fin du programme ;--------------------------------------------------------------------- ou ;----------------------Programme 5------------------------------------ Start: Move.l #%0010100101010000,D0 And.l #%0110011101110000,D0 Rts ; Fin du programme ;--------------------------------------------------------------------- On trouve après exécution de ce programme le résultat dans d0. Pour bien être sûr du résultat vous pouvez taper comme commande sous Asm-One : '? $2150'. On retrouve bien ce que nous avions en binaire. EXEMPLE ~~~~~~~ Mais concrètement, à quoi ça sert ce truc ? L'utilisation la plus courante (pour moi en tout cas) est la création de masques. Par exemple on a le nombre binaire : 11011 et je ne veux pas m'occuper des deux derniers bits, c'est à dire que je veux garder que les trois premiers. Donc je vais créer un masque qui filtre uniquement les trois premiers bits. Eh bien le masque peut être fait facilement avec l'instruction 'And'. Donc si je fais 11011 AND 11100 = 11000 (Valeur) (Masque) (Résultat) J'ai bien les trois premiers bits et j'ais viré les deux derniers. ;----------------------Programme 6------------------------------------ Start: Move.l #$fedf1234,d0 And.l #$0000ffff,d0 Rts ; Fin du programme ;--------------------------------------------------------------------- Dans ce petit exemple, je ne veux garder que les 16 premiers bits de d0. Donc le Résultat sera $00001234. OR : C'est le 'ou' logique. ~~ Voici sa table de vérité: \ 0 | 1 | --|-------| 0 | 0 | 1 | --|-------| 1 | 1 | 1 | ----------- Si vous avez bien compris le 'AND', et bien c'est pareil. Ici, pour avoir un 1 en sortie, il faut au moins un 1 dans une des sources. Le 'Or' est utilisé pour forcer à 1 une série de bits. Syntaxe : Or #Valeure,Dx Syntaxe : Or Dx,Dx ;----------------------Programme 7------------------------------------ Start: Move.l #$abcd1234,d0 And.l #$0000ffff,d0 Rts ; Fin du programme ;-------------------------------------------------------------------- Le Résultat sera $abcdffff. Les 16 derniers bits ont été forcé à 1 EOR : C'est le 'ou exclusif' logique. ~~~ Voici sa table de vérité: \ 0 | 1 | --|-------| 0 | 0 | 1 | --|-------| 1 | 1 | 0 | ----------- Ici, pour avoir un 1 en sortie, il faut avoir un seul dans les deux sources. Syntaxe : Eor #Valeure,Dx Syntaxe : Eor Dx,Dx J'utilise cette instruction pour calculer des compléments. ;----------------------Programme 8------------------------------------ Start: ; On veut calculer le complément de 10 à 63...(C'est 53 bien sur!) Move.w #10,d0 ; Methode normale Move.w #63,d1 Sub.w d0,d1 ; D1 = 54 ; Avec le Eor Eor #63,d0 ; Meme chose en une instruction ; Voila Rts ; Fin du programme ;--------------------------------------------------------------------- Cette méthode ne marche qu'avec des compléments de multiples de 2 (-1)! Cherchez pourquoi... I Instructions : CMP BTST TST Bcc (Comparaisons et tests) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 'Cmp' signifie 'CoMPare'. Donc comme son nom l'indique ça sert à faire des comparaisons. Cette instruction est utilisée avec une instruction de branchement conditionnel. Syntaxe : Cmp Registre,Registrex Syntaxe : Cmp #Valeur,Registre Syntaxe : Cmp #Valeur,Adresse Syntaxe : Cmp Adresse,Registre Et tout ça bien sur en .l, .w ou même .b ... Voici tout de suite un petit exemple concret : ;---------------------Programme 9------------------------------------- Start: Move.w #10,d0 ; D0 = 10 Cmp.w #10,d0 ; Compare 10 et d0 Beq .ok ;Si c'est egal alors on saute à .ok. Move.b #1,Flag .ok Rts ; Fin du programme Flag: Dc.b 0 ;--------------------------------------------------------------------- Cet exemple est vraiment idiot, j'en conviens mais il faut que ça rentre d'une manière ou d'une autre (Hein l'ours, t'es d'accord !). Donc après un 'Compare' on utilise un 'Bcc'. (cc veut dire 'condition') Cmp.w #10,d0 -> 'Compare' Beq .ok -> 'Bump if Equal' En basic on aurait -> IF D0=10 THEN GOTO .ok On peut utiliser aussi 'BNE' -> 'Bump if Not equal' Il existe toute une liste de 'Bcc' telle que Bpl, bmi, bge, blt... On peut se limiter à l'utilisation de 'Bpl' et 'Bmi' pour le 'supérieur à' et 'l'inférieur à' ;---------------------Programme 10------------------------------------ Start: Move.w #10,d0 ; D0 = 10 Cmp.w #40,d0 ; Compare 40 et d0 Bpl .ok ; Si le résultat est positif alors saut à .ok Move.b #1,Flag .ok Rts ; Fin du programme Flag: Dc.b 0 ;-------------------------------------------------------------------- Bon ici il faut faire une petite gymnastique spirituelle. Toutes les instructions 68000 sont comme je dirais 'Instinctive' contrairement à Intel par exemple. Donc les instructions instinctives c'est de mettre la source à gauche et la destination à droite. Donc quand on écrit 'Move #10,d0', on met 10 vers D0... Mais, car il y a un mais, 'Cmp' est la seule instruction non instinctive. Si on fait un 'CMP A,B', la machine réalisera l'opération B-A. Le résultat ne sera pas explicite mais la machine gardera en mémoire si ce résultat est positif, négatif ou égal à zero. Donc ici... D0=10 Cmp.w #40,d0 ; La machine exécuté 10-40=-30 ; Donc le résultat est négatif. Bpl .ok ; 'Bump if plus' ; On saute si c'est positif. ; Donc ici, on saute pas. ; Si on a pas sauté, on est ici et après on passe par .ok bien sur .ok ; Si on a sauté, on est venu ici sans passer par la case ; départ et sans toucher 20000. * 'Btst' signifie 'Bit TeSt'. On test si un bit est à 0. Essayez ce programme, il est marrant : ;---------------------Programme 11------------------------------------ ST: Move.b $dff006,$dff180 ; Eh eh ... Btst #6,$bfe001 ; Test du 6eme bit de l'octet de ; l'addresse $bfe001 Bne St ; Si il est egal à 0 on saute à St. Rts ;--------------------------------------------------------------------- Pour sortir, on appuie sur le bouton gauche de la souris. Le bit 6 de l'octet contenu à l'adresse $bfe001 correspond à l'état du bouton gauche de la souris. * 'Tst'. Cette instruction est équivalente à un 'Cmp #0,...' I Instructions : LSL LSR (Décalages) ~~~~~~~~~~~~~~~~~~~~~~~~ * 'LSR et LSL' signifient 'Logic Shift to Right' et 'Logic Shift to Left' Ce sont justes des décalages de bits vers la droite ou la gauche. Par exemple. On veut décaler %11010 vers la droite d'un cran. ;----------------------Programme 12----------------------------------- ST: Move.b #%00011010,D0 Lsr #1,D0 ; Décale d'un cran vers la droite ; Donc D0=00001101 Rts ;--------------------------------------------------------------------- Voila c'est simple. On peut décaler de 1 à 8 crans. Et selon les goûts et les désirs on peut utiliser d'autres instructions comme : 'ROR ROL er ASL ASR' L'avantage de ce genre d'instructions est que l'on peut faire des divisions et des multiplications. C'est beaucoup beaucoup plus rapide de décaler des bits que de faire un algorithme de multiplication. Pour multiplier, on décale vers la gauche. Chaque bit correspond à une puissance de 2. Donc pour multiplier par 2, on décale vers la gauche une fois. Si on veut multiplier par 4, on décale deux fois.. etc etc Et pareil pour la division avec le décalage à droite. Donc si on décale n fois, on multiplie ou on divise par 2 puissance n. ;----------------------Programme 13----------------------------------- ST: Move.w #7,D0 ; D0 = 7 ; Ce qu'il faut pas faire : Mulu.w #4,D0 ; Multiplication par 4 !!! aie aie ; Ce qu'il faut faire : Lsl.w #2,d0 ; Décalage de 2 cran sur la gauche ; = Multiplication par 4 (2 puissance 2) Rts ;--------------------------------------------------------------------- I Instructions : MOVEQ ADDQ SUBQ (Instructions rapides) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 'MoveQ' est le 'Quick Move'. C'est une instruction optimisée pour faire des 'Move' de petites valeurs. Enf fait ça marche juste avec des entiers entre 0 et 7 !!! (C'est a dire codé sur 3 bits) Cette instruction ne fonctionne qu'avec des registres de données. Syntaxe : Moveq #Valeur,Dx (Avec une valeur comprise entre 0 et 7) * 'AddQ' ben pareil que 'Moveq' sauf que ça marche avec tout. Syntaxe: Addq #Valeur,Dx (Avec une valeur comprise entre 0 et 7) Syntaxe: Addq #Valeur,Ax (Avec une valeur comprise entre 0 et 7) Syntaxe: Addq #Valeur,Adresse (Avec une valeur comprise entre 0 et 7) * 'SubQ' ben tout pareil que Miguel. No comment. I Instructions : MULU DIVU ( Multiplication et Divisions) ~~~~~~~~~~~~~~~~~~~~~~~~~~ Pas de commentaire sur ces fonctions, elle sont assez explicites. * 'Mulu' est la multiplication non signée. La plus utilisée. Syntaxe : Mulu.l #Valeur,Registre Syntaxe : Mulu.w #Valeur,Registre Syntaxe : Mulu.l Registre,Registre Syntaxe : Mulu.l Registre,Registre La multiplication signée est obtenue avec 'Muls'. * 'Divu' est la division non signée. La division 'longue' : Syntaxe : Divu.l #Valeur,Registre Syntaxe : Divu.l Registre,Registre Elle divise un long (32 bits) par un long et le résultat est sur un long. La division en 'Word' : Syntaxe : Divu.w #Valeur,Registre Syntaxe : Divu.w Registre,Registre Le principe est le même mais ici le résultat est différent. On trouve sur les 16 bits de poids faible la partie entière et sur les 16 bits de poids fort le reste de la division. De même la division signée sera 'Divs'. ;---------------------Programme 14------------------------------------ ST: Clr.l d1 Clr.l d2 Move.l #10,d0 ; D0 = $0000000A Mulu.l #40,d0 ; D0 = $00000190 Divu.w #13,d0 ; D0 = $000A001E ; Reste~~~~~----Partie Entière ; Pour récupérer la partie entière, il suffit de lire le registre ; d0 en mot Move.w d0,d1 ; Transfert des 16 bits de poids faible ; Pour récupérer le reste ($000A), il faut décaler le registre ; 16 fois vers la droite (Sauvage!) ou utiliser la commande 'Swap' ; (Bien mais faut lire le paragraphe d'après!). Swap d0 Move.w d0,d2 ; Transfert les 16 bits de poids faible Rts ;--------------------------------------------------------------------- Donc voila la multiplication et la division. Il ne faut pas oublier que ces instructions sont des opérations assez compliquées donc elle prennent un peu plus de temps en exécution que les autres instructions. Alors si vous pouvez éviter d'utiliser des multiplications et des divisions dans vos sources et ben faites le. Et je rappelle que pour faire des multiplications et des divisions par des multiples de 2 IL FAUT utiliser les décalages. I Instructions : SWAP EXT EXG ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 'Swap' signifie 'Swap' eheh. Cette instruction permet d'échanger les 16 bits de poids faible et les 16 bits de poids fort d'un registre. Cette instruction ne s'utilise que sur les registres de données. Syntaxe : Swap Dx ;----------------------Programme 15----------------------------------- Start: Move.l #$abcd1234,d0 Swap d0 Rts ; Fin du programme ;--------------------------------------------------------------------- On aura dans d0: $1234abcd Cette instruction est utile (si si!) par exemple pour le résultat d'une division. On a vu que le reste de la division est stocké sur les 16 bits de poids fort. Un 'Swap' permet de le récupérer directement. * 'Ext' signifie 'Extend'. Elle permet d'étendre le signe d'un nombre 16 bits (ou 8 bits). On peut ainsi utiliser ce nombre comme un nombre 32 bits (ou 16 bits) car son signe est conservé. Cette instruction ne s'utilise que sur les registres de données. Syntaxe : Ext.w Dx ( extension 8 -> 16 ) Syntaxe : Ext.l Dx ( extension 16 -> 32 ) Exemple: le nombre $f000 en 16 bits signé est égal à -4096 Si on veut l'utiliser en 32 bits sans étendre son signe on aura $0000f000 qui est égal à 61440...aie Donc on étend le signe de $f000 et on obtient $fffff000 qui est lui bien équivalent à -4096. L'opération d'extension de signe consiste simplement à recopier le bit de poid fort (c'est le signe!) Sur les 16 bits que l'on ajoute devant. * 'Exg' Signifie 'Exchange'. Cette instruction permet d'échanger le contenu de deux registres. Syntaxe : Exg Registre,Registre I Instructions : MOVE (Ax,Dx),Dest MOVE (Ax)+,dest ( Autres 'Moves' ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Voici quelques utilisations étendues du 'Move'. * Lorsqu'on fait 'Move (ax),d0', on met dans D0 le contenu de la case mémoire dont l'adresse est contenue dans a0. Voici un exemple : ------------------------ Admettons qu'a partir de $20000 on ait: $14 $18 $21 $52 $36 .... ------------------------ ( c'est a dire .... dans la case $20000 il y a $14, dans la case $20001 il y a $18, dans la case $20002 il y a $21... ) ;---------------------Programme 16------------------------------------ Start: ; Move.l #$20000,A0 ; Dans a0 on met $20000 ; Mais ici, on remplace cette adresse par une autre ; car c'est très sale d'utiliser des adresses absolues... Move.l #Datas,A0 ; Voila c'est mieux ;---------------------- Move.b (A0),D0 ; D0 reçoit le contenu de la case $20000 ; C'est a dire $14 Move.w (A0),D1 ; D1 reçoit $1418 Move.l (A0),D2 ; D2 reçoit $14182152 ;----------------------- Move.b 2(A0),D3 ; D3 reçoit $21 ;----------------------- Move.w #2,D4 Move.b (A0,D4.w),D5 ; D4 reçoit $21 également ;----------------------- Move.b (A0)+,D6 ; D6 reçoit $14 et on ajoute "1" à A0 Move.b (A0)+,D7 ; D7 reçoit $18 et on ajoute "1" à A0 Rts ; Fin du programme Datas: Dc.b $14,$18,$21,$52,$36 ;--------------------------------------------------------------------- * 'Move nb(Ax)' c'est la même instruction que précédemment mais on peut se servir d'un index. Syntaxe : Move nb(Ax),Dx Syntaxe : Move nb(Ax),Adresse * 'Move (Ax,Dx)' c'est un 'Move' avec un index mais contrairement à l'instruction d'avant où l'index était fixe,ici l'index est le contenu d'un registre donc on peut le faire varier au cours du programme. Syntaxe : Move (Ax,Dx.w),Dx Syntaxe : Move (Ax,Dx.w),Adresse On peut aussi ajouter une multiplication du registre d'offset : Syntaxe : Move (Ax,Dx.w*2),Dx * 'Move (Ax)+' est un 'Move' avec une incrémentation automatique du registre Ax. Cette incrémentation est fonction de la taille de l'élément que l'on déplace. Par exemple, si on fait 'Move.b (a0)+,d0', on copie dans d0 un octet donc a0 sera incrémete de "1" pour pointe sur l'octet suivant. Avec un 'Move.w (a0)+,d0', on déplace un mot (= 2 octets) donc a0 sera incrémenter de "2". Et logiquement pour un 'Move.l (a0)+,d0' a0 sera incrémenter de "4" (1 long= 2 mots= 4 octets). Syntaxe : Move (Ax)+,Dx Syntaxe : Move (Ax)+,Adresse Syntaxe : Move (Ax)+,(Ax)+ Syntaxe : Move Dx,(Ax)+ On peut utiliser aussi la décrémentation. 'Move.w -(a0),d0'. Le "-" se place devant car la décrémentation est effectuée avant le move. ;--------------------Programme 17------------------------------------- Start: Clr.l D0 Clr.l D1 Move.l #Datas,A0 ; Voila c'est mieux Add.l #2,A0 ; A0 pointe sur le début de la table + 2 ; C'est a dire $21 Move.b (A0),d0 ; D0 reçoit $21 Move.b -(A0),D1 ; A0=A0-1 et D1 reçoit $18 Rts Datas: Dc.b $14,$18,$21,$52,$36 ;--------------------------------------------------------------------- I Instructions : LEA MOVEM ~~~~~~~~~~~~~~~~~~~~~~~~~~ * 'Lea' signifie 'Load Effective Address'. Cette instruction ne s'utilise qu'avec les registres d'adresses (a0 a1 a2 a3 a4 a5 a6 a7). Syntaxe : Lea Valeur,Ax Cette instruction sert à charger une adresse dans un registre. On pourrait aussi écrire 'Move.l #Valuer,Ax' * 'Movem' est le 'Move multiple'. Il permet de transférer plusieurs registres en une seule instruction. On l'utilise en général pour sauvegarder tous les registres dans la pile. Movem.m D0-D7/A0-A6,-(a7) ; empile les registres. Movem.l (a7)+,D0-D7/A0-A6 ; depile les registres. Voilà c'est pas compliqué, remarquez juste qu'on utilise la pile à l'envers. C'est une coutume. I Instructions : Dc Blk ( Assemblage direct de données ~~~~~~~~~~~~~~~~~~~~~~~ et réservation de zones mémoires) * 'Dc' est utilisé pour coder directement des données en mémoire. Voici un exemple: ;--------------------Programme 18------------------------------------- Start: ; Rien Rts Data1: Dc.b $14,$18,$21,$52,$36,'q','b',%00000111,12,10 Even Data2: Dc.w $0000,$0001,$0002,$1545,$7879 Dc.w $10+14,45-80,$FFFF>>2 Data3: Dc.l $00201451,$01568754,$45687321,$44654654 ;--------------------------------------------------------------------- C'est simple... à l'adresse 'Data1' on a assemblé des octets. à l'adresse 'Data2' on a assemble des mots. Un mot ne peu pas être sur une adresse impaire. Par exemple 'Move.w #1,$20001' ne marche pas. Donc pour cette raison, on ajoute une instruction 'Even' qui recale l'adresse 'Datas2' sur une adresse paire. Vous avez dans ce petit programme quelques exemples de syntaxes qu'accepte Asm-one. le '>>' signifie décalage. * 'Blk' est l'instruction qui permet de réserver une zone mémoire. Par exemple si vous voulez réserver 10 octets pour travailler vous pouvez taper : Dc.b 0,0,0,0,0,0,0,0,0,0 ou Blk.b 10. La deuxième solution étant la bonne bien sûr. Vous pouvez remplir ces données réservées par un motif... Par exemple 'Blk.b 10000,$ff' réservera 10000 octets et ils seront tous initialisés à $ff au depart. On peut aussi faire des 'Blk.w' ou des 'Blk.l'. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Voila, c'est fini pour aujourd'hui. J'espère que l'essentiel est compris. Si ce n'est pas le cas ou s'il reste des zones de flous, ne vous inquiétez pas les éclaircissements viendront avec l'expérience. On peut pas tout comprendre clairement d'un coup et je ne peux pas non plus tout vous expliquer avec exactitude. Je vous laisse une partie de la programmation à comprendre par vous même. L'assembleur c'est aussi une façon de réfléchir et ça je ne peux pas le faire pour vous alors il va falloir faire fonctionner le petit vélo. Pour avoir quelques compléments je vous conseille de feuilleter des livres genre 'MC 68000' ou tout autre ouvrage du genre qui décrit le fonctionnement du 68000. Et par la même occasion, trouvez vous la bible de l'amiga. C'est essentiel pour aller plus loin. Le cours prochain, on attaque les choses sérieuses. Je vous donnerai une ossature de programme pour faire tourner vos routines. Cette ossature sera le point de départ de vos démos. Je vous expliquerai comment on utilise un écran et on essaiera de faire une belle routine avec des trucs qui bougent (enfin!). Et vous méditerez pour la prochaine fois cette pensée shadock : " Plus ça rate, plus on a de chance que ça réussisse ! " \|/ (o o) ---------oOO-----OOo------ Oriens/ Les Oo Shadock \/ christophe.kohler_ché_wanadoo.fr --------(_)------(_)------ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Petit lexique de l'assembleur débutant : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Traceur: C'est l'opération qui consiste à exécuter le programme en temps réel, ligne par ligne. On peut voir l'évolution des registres ainsi que n'importe quel case mémoire. Très utile pour debugger. Booléen : Variable qui ne peut prendre que deux valeurs : 0 et 1. Assembler : Opération, effectuée par l'assembleur, qui consiste a transformer votre beau listing avec de belles instructions en une série de 1 et de 0 où plus grand chose n'est compréhensible. Chip : Partie intérieure de la mémoire. Cette partie est accessible par tous les organes de l'amiga. Les accès y sont cependant un peu lent. Debugger : Trouver les bugs. Quand ça marche pas, c'est qu'il y a un bug. C'est comme une erreur mais ça s'appelle un bug. Bref tant que ça marche pas il faut chercher les bugs, c'est l'opération de debuggage. En général c'est ce qui prend le plus de temps. Bon pour la petite histoire, un 'bug' en anglais c'est tout ce qui est petit et qui rampe. Vers les année 60, les ordinateurs étaient énormes, plus gros que des PCs, et il fallait plusieurs salles pour les stocker, et des kilomètres de gros câbles. Et les 'bug', cette bande d'improductifs insectes, n'avaient rien de mieux a faire que de bouffer les câbles. Donc ça faisait tout planter et on a juste gardé le nom de 'bug'. Donc pas la peine d'aller chercher votre BAYGON jaune quand vos programmes plantent. Fast : La mémoire fast est la partie mémoire se trouvant à des adresses plus lointaines que la chip. Ce type de mémoire n'est pas inclus dans l'amiga 1200 de base. A cause de la taille des adresses de la mémoire fast, certains organes de l'amiga comme le copper, les dmas et le blitter, ne peuvent pas y accéder. Cependant, cette mémoire est - comme son nom l'indique - plus rapide que la chip. Source : c'est le texte que vous tapez sous l'éditeur. L'assembleur aura pour tache de transformer ce texte en code machine compréhensible par l'amiga. Syntaxe : C'est la grammaire de l'ordinateur. Pour écrire les instructions il faut suivre certaines règles sinon l'assembleur ne comprend pas. Tabulations : C'est la seconde touche en haut a gauche (avec les flèches dans les deux sens). Cela permet d'aligner les instructions. Mais le plus important c'est que TOUTES instructions sont precedées d'une tabulation, sinon elles sont considérés comme des labels. Registre : Voir cours 1 Processeur : Voir cours 1 Petit vélo : Le petit vélo, c'est le truc que vous avez dans la tête et qui vous sert à réfléchir (hein Kuma !).