Sie sind auf Seite 1von 21

LE LANGAGE MACHINE & L'ASSEMBLEUR

Ce chapitre constitue une tape importante, car c'est le premier qui traite du langage. Il dcrit le plus rudimentaire des langages informatiques, le langage machine, ainsi que son alter ego humain, lassembleur.

RECAPITULONS
En fait, la manire de Monsieur Jourdain, nous avons dj utilis ces deux langages, sans le savoir : le langage machine et l'assembleur. Si nous reprenons le tableau indiquant le contenu de la ROM1 dans le sous-chapitre Optimisation de la ROM / 2 ROM du chapitre prcdent, le lien entre langage machine et l'assembleur est le suivant : Langage machine 00h 01h 02h 03h 04h 05h Assembleur NOP ADD Acc,M MOV Acc,D MOV D, Acc AND Acc,H etc

Nota : NOP signifie No OPeration (pas d'opration). Cette instruction n'excute aucune tche, si ce n'est de passer la suivante en ralisant uniquement le cycle fetch. L'expression en langage machine d'une instruction en assembleur est la valeur inscrire en RAM pour excuter l'opration (c'est--dire le Code Opration), suivie ventuellement de ses oprandes aux adresses suivantes. Le microprocesseur que nous avons construit prsentait lintrt dtre simple, donc pdagogique. Pour aborder lapprentissage du langage dans un monde plus rel, nous allons maintenant utiliser le microprocesseur rel Z80, dont les principes de fonctionnement sont les mmes que pour notre microprocesseur fantme, mais qui prsente cependant quelques diffrences, certaines de pure convention (comme le nom donn aux registres), dautres de fonctionnement (comme le fait que certains rsultats doprations aillent directement dans un registre dtermin sans passer par Acc), mais dans ce dernier cas, il sagit souvent de fonctions labores qui nont pas leur place dans un ouvrage ddi une initiation.

LE Z80

Sa structure

Le langage machine, lassembleur

Page 1

Ses registres
Les registres du Z80 sont les suivants : accumulateur : a. registres de donnes 8 bits : b, c, d, e, h, l. registres de fonctionnement 8 bits : - f : drapeaux. Le contenu de ses 8 bits est SZXHXPNC o, suivant le rsultat de lopration prcdente : > S : est 1 pour un rsultat ngatif, 0 sinon. Peu utilis. > Z : est 1 pour un rsultat nul, 0 sinon. Trs utilis. Attention linversion apparente de logique (on aurait pu croire que Z soit 0 pour un rsultat 0) : Z prend la valeur boolenne de lassertion le rsultat est Zro , cest--dire 1 si cest vrai, 0 sinon. > X : inutiliss. > H : demi-retenue. Utilis pour le codage BCD (Binaire Cod Dcimal), que nous ne dvelopperons pas. > P : appel en ralit P/V (Parity / oVerflow = parit / dbordement), modifi notamment suivant le nombre (pair ou impair) de bits 1 du rsultat. Trs peu utilis. > N : indique si la dernire opration tait une addition ou une soustraction. Utilis pour le codage BCD (Binaire Cod Dcimal), que nous ne dvelopperons pas. > C : est 1 pour un rsultat ayant gnr une retenue, 0 sinon. Trs utilis. - i : gestion des interruptions. Nous ne dtaillerons pas son fonctionnement ici. - r : rafrachissement de la mmoire. Nous ne dtaillerons pas son fonctionnement ici. registres de donnes 16 bits : - bc, de, hl : registres issus du jumelage des registres 8 bits. Par exemple, si B=9Dh et C=A3h, alors BC=9DA3h. Inversement, si BC=9DA3h, alors B=9Dh et C=A3h. - ix et iy : purs registres 16 bits, dont le nom est propre et ne signifie en rien un jumelage des registres i et x dune part, et i et y dautre part. ix est utilis via le prfixe DDh, prcdant les oprations sur hl et permet de remplacer ce dernier par ix+n. Par exemple, le code assembleur AEh ralise lopration XOR (hl). Le code assembleur DDh AEh A3h ralise lopration XOR (ix+A3h). iy est utilis de mme que ix, mais avec le prfixe FDh au lieu de DDh. registres de fonctionnement 16 bits : - sp : Stack Pointer - pc : Program Counter - af : registre issu du jumelage des registres 8 bits a et f, que lon retrouve dans quelques instructions sous cette forme. Ce nest pas un registre ayant une valeur de donne 16 bits, mais ce jumelage permet de manipuler en une fois tout ce qui touche un rsultat : sa valeur (dans a) et son effet sur les drapeaux (dans f). Le langage machine, lassembleur Page 2

Tous les registres 8 bits (sauf r et i qui sont peu utiles au programmeur) ont un registre-doublon (portant le mme nom, mais avec une apostrophe : a, b, c, d, e, h, l, f), auxquels on accde par le biais dinstructions dchange entre le registre et son doublon.

Ses instructions
Avec le Z80, les instructions (notamment leurs codes assembleur associs) ne sont plus celles que nous avons labores dans le prcdent chapitre, mais celles prsentes en annexe 1, nanmoins trs voisines. Il existe cinq jeux (pour reprendre le vocabulaire du chapitre Le microprocesseur ) dinstructions : colonne Seul de lannexe 1 : jeu de base, comprenant notamment les prfixes CBh, DDh, EDh et FDh qui ouvrent les autres jeux. colonne Aprs CBh de lannexe 1 : instruction excutes lorsque le Code Opration est prcd de CBh en RAM. colonne Aprs EDh de lannexe 1 : instruction excutes lorsque le Code Opration est prcd de EDh en RAM. colonne Aprs DDh de lannexe 1 : ce pseudo-jeu qui reprend en fait le 1er jeu dinstructions, en permettant un adressage index dans les instructions utilisant loprande hl . Avec ce prfixe, loprande hl du premier jeu dinstruction est remplac par ix , ou ix+n suivant le cas. A ce titre, il ne sagit pas strictement dun jeu supplmentaire, car il napporte pas de nouvelles instructions : il ne fait que modifier lune des oprandes dinstructions dj vues. Le prfixe DDh peut tre cumul avec le prfixe CBh (colonne Aprs DDh CBh de lannexe 1). Un 5me pseudo-jeu, qui reprend les mmes instructions que le prcdent, mais utilise le registre dindexation iy au lieu de ix. Cela est ralis en utilisant le prfixe FDh au lieu de DDh. La fonction des diverses instructions est dcrite en annexe 2. La liste des instructions peut paratre compltement dsordonne, arbitraire. A y regarder de plus prs, on remarque par exemple que les Codes Opration de 40h 7Fh (cest--dire sur une liste de 40h qui est un chiffre rond en hexadcimal Codes Opration) ne tombent pas du ciel tout cuits, mais semblent provenir dune construction volontaire : la premire oprande passe en revue les valeurs b, c, d, e, h, l, (hl) et a, puis pour chacun deux la deuxime oprande aussi. En effet, une analyse plus fine de lcriture binaire des Codes Opration du jeu de base rvle la structure suivante :

Le langage machine, lassembleur

Page 3

Code Opration (binaire) (un point signifie : 0 ou 1, en gras : chiffres changeant dune ligne la suivante) 00 00000 000..000 00001 00010 00011 00100 00101 00110 00111 01 01xxxyyy sauf 01110110 01110110 10 10cccxxx 11 11000 11001 11010 11011 001..001 00..0001 00..1001 00..0010 00..1010 00..0011 00..1011

000..111 001..111

00..0001 00..1001 00000011 00001011 0001.011 0010.011 0011.011

11100 11101

11110 11111

00..0101 00..1101 sauf 00001101 00001101 CALL nn CCC a,n o CCC = RST

Oprateur Oprateur et/ou oprande(s), selon la valeur de , de .. ou de . (points = 000 001 010 011 100 101 110 111 oprateur et / 00 01 10 11 ou oprande) 0 1 Divers NOP EX DJNZ n JR n af,af JR .. n nz z nc c LD ..,nn bc de hl sp ADD hl,.. bc de hl sp LD .. bc,a de,a (nn),hl (nn),a LD .. a,bc a,de hl,(nn) a,(nn) INC .. bc de hl sp DEC .. bc de hl sp INC b c d e h l (hl) a DEC b c d e h l (hl) a LD ,n b c d e h l (hl) a Rotations RLCA RRCA RLA RRA Divers DAA CPL SCF CCF LD xxx,yyy o xxx = b c d e h l (hl) a yyy = b c d e h l (hl) a HALT CCC a,xxx o CCC = ADD ADC SUB SBC AND XOR OR CP xxx = b c d e h l (hl) a RET nz z nc c po pe p m POP .. bc de hl af Divers RET EXX JP (hl) LD sp,hl JP nn nz z nc c po pe p m JP nn Prfixe CBh IN / OUT OUT n,a IN a,n EX . (sp),hl de,hl Interruptions DI EI CALL nn nz z nc c po pe p m PUSH .. bc de hl af Prfixes DDh EDh FDh

ADD 00h

ADC 08h

SUB 10h

SBC 18h

AND 20h

XOR 28h

OR 30h

CP 38h

Par exemple, le Code Opration 10100010 signifie AND a,d, le Code Opration 11011010 signifie JP c nn. On distingue bien par exemple que les bits 3 5 du Code Opration peuvent tre traits via un multiplexeur, situ non pas sur les bits de donnes du microprogramme, mais directement sur les bits du Code Opration. On peut supposer que ce multiplexeur est par contre activ par un bit du microprogramme, ou par une logique combinatoire sur les autres bits du Code Opration.

Le langage machine, lassembleur

Page 4

#Schma ?

MISE EN JAMBES Premier exemple


Nous allons crire un petit programme qui additionne 26h et 1Eh, et met le rsultat dans d. Nous plaons notre programme partir de l'adresse 0100h de la RAM. Ce qu'il y a dans la machine Adresse Code (hexa) (hexa) 0100 3E 0101 26 0102 16 0103 1E 0104 82 0105 57 0106 C9 Ce que l'humain peut raisonnablement comprendre Mnmonique Commentaire LD a,26h LD d,1Eh ADD a,d LD d,a RET Octet du Code Opration Octet de l'oprande Octet du Code Opration Octet de l'oprande Octet du Code Opration (pas d'oprande expliciter) Octet du Code Opration (pas d'oprande expliciter) Octet du Code Opration (pas d'oprande)

La dernire opration spcifie que c'est la fin du programme. Nous y reviendrons plus tard. Le langage machine est ce qui est directement utilisable par la machine : c'est une suite de nombres dans la RAM (celle de la deuxime colonne), suite ayant certes une signification prcise pour le microprocesseur, mais trs peu parlante pour l'humain moyen : il ne saute pas aux yeux que la suite hexadcimale 3E / 26 / 16 / 1E / 82 / 57 / C9 ralise une addition. Pour qu'un programme en langage machine devienne prsentable, lhumain associe chacun des Codes Opration un court texte qui rsume sa fonction et remplace avantageusement lhermtique Code Opration hexadcimal : c'est le mnmonique, que nous avons dj vu. Celui-ci se dcompose en une opration, et ventuellement une ou des oprandes. Ainsi, le Code Opration 3Eh signifie : prendre l'octet suivant dans la RAM et l'crire dans a. Le mnmonique associ est LD a,n (n signifie : valeur numrique sur 1 octet, prcise en oprande en adressage immdiat , ce qui est logique puisquil sagit de la copier dans a, qui tient sur 1 octet). Reste inscrire la valeur de n (l'oprande) dans l'adresse immdiatement suprieure celle qui contient le Code Opration 3Eh (puisque cest l que le microprogramme de linstruction lattend) : c'est ce que nous avons fait l'adresse 0101h. Si cet octet contient 26h, le mnmonique spcifique ce cas-ci devient LD a,26h. Lhumain pense ses programmes en assembleur, puis, une fois crit, le programme doit ncessairement tre traduit en langage machine. Cette opration sappelle l assemblage (lopration inverse tant le dsassemblage ). Pour bien la comprendre, nous la ralisons ici la main (grce aux correspondances Code Opration / mnmonique indiques dans lannexe 1), mais cest une opration aujourdhui compltement automatise. La prochaine instruction doit donc prendre place l'adresse 0102h. Le Code Opration 82h signifie : additionner a et d, puis mettre le rsultat dans a. Le mnmonique associ est ADD a,d. Ce Code Opration se suffit lui-mme, car l'oprande est implicitement comprise dans le Code Opration. L'adresse suivante en RAM contient donc non pas une oprande, mais la prochaine instruction. Le tableau ci-dessus est plus souvent reprsent de la manire suivante :

Le langage machine, lassembleur

Page 5

Adresse (hexa) 0100 0102 0104 0105 0106

Code (hexa) 3E 26 16 1E 82 57 C9

Mnmonique LD a,26h LD d,1Eh ADD a,d LD d,a RET

Commentaire

Deuxime exemple
Par de simples additions successives, ralisons maintenant la multiplication de 1Dh par 05h. Adresse (hexa) 0100 0102 0104 0106 0107 0108 Code (hexa) 3E 00 16 1D 06 05 82 05 C2 06 10 Mnmonique LD a,00h LD d,1Dh LD b,05h ADD a,d DEC b JP nz 0106h Commentaire Initialisation de a 0 Multiplicande dans d Multiplicateur dans b Calcul du rsultat partiel Dcrmentation du multiplicateur, avec modification des drapeaux : notamment, z est mis 0 si b reste diffrent de 0, mais est mis 1 si b atteint 0 aprs la dcrmentation. Saut l'adresse 0106h si NZ est vrai, cest--dire si Z est faux, cest--dire si le rsultat de la dernire opration nest pas 0, cest--dire si b 0. Comme pour toute valeur 16 bits, ladresse de saut est inscrite en RAM en mettant loctet de poids faible avant loctet de poids fort, ici 06h ladresse 0109h, et 10h ladresse 010Ah. Enregistrement du rsultat dans d Fin

010B 010C

57 C9

LD d,a RET

Voici le principe de ce petit programme : a est destin contenir le rsultat intermdiaire. Aprs l'avoir au pralable initialis 0, on va, 05h reprises, additionner 1Dh a. d contient la multiplicande (la valeur additionner a) b contient le multiplicateur, vu comme un compteur (combien de fois a-t-on additionn 1Dh a ?) Aprs avoir additionn d a, on dcrmente b. Si alors b>0, cela signifie que nous n'avons pas additionn d a suffisamment de fois. Il faut donc rpter l'opration d'addition. C'est le rle tenu par l'instruction JP nz 0106h : si le rsultat de la dcrmentation de b n'est pas nul, on ralise un saut l'adresse 0106h, ce qui rpte le cycle d'addition / dcrmentation / saut ventuel. Sinon, on passe linstruction suivante dans la RAM, ce qui clt le cycle. Si l'opration est termine, on transfre le rsultat final de a vers d, pour librer a, qui nous resservira certainement plus tard. L'ensemble des instructions des adresses 0106h 010Ah est appel boucle (reprsente par la flche) : un compteur (ici le registre b) dtermine le nombre de fois o cet ensemble d'instructions doit tre excut. L'adresse indique par l'instruction JP nz dtermine o la boucle commence. L'adresse de l'instruction JP nz dtermine o la boucle se termine. Les boucles sont trs souvent utilises dans tous les langages de programmation. Tellement mme que le Z80 est dot dune instruction assembleur spcifique : DJNZ dis (dis tant loprande). DJNZ dis ralise les oprations suivantes : DEC b Si Z=1 (cest--dire si DEC b a donn un rsultat nul, cest--dire si b=0), alors JR dis. Sinon, le programme continue linstruction suivante. Notez que le saut est relatif (JR et non JP). Le registre b est utilis comme compteur de la boucle. Il est cens tre initialis la valeur voulue en amont de la boucle. La construction typique dune boucle est la suivante :

Le langage machine, lassembleur

Page 6

Adresse Prog

Code (hexa)

Mnmonique Diverses oprations LD b,compteur

Commentaire Comprend notamment les oprations prparatoires la boucle. compteur est le nombre de fois o la boucle doit tre parcourue. Dbut de la boucle.

06 compteur Boucle

Fin

10 Boucle-Fin-2

Fin+2

Premire opration rpter Autres oprations rpter DJNZ Boucle Le -2 provient du fait quil sagit dun dcalage par rapport PC qui a dj t mis jour, par le microprogramme de DJNZ, pour pointer sur linstruction suivante. Or, DJNZ dis occupant 2 octets en RAM, linstruction suivante se situe ladresse Fin+2. PC a donc pour valeur Fin+2, do le -2 pour compenser cette anticipation. Reste du Sortie de la boucle. programme

Dans lexemple prcdent (multiplication de 1Dh par 05h), le programme serait : Adresse (hexa) 0100 0102 0104 0106 0107 0109 010A Code (hexa) 3E 00 16 1D 06 05 82 C2 FD 57 C9 Mnmonique LD a,00h LD d,1Dh LD b,05h ADD a,d DJNZ 3d LD d,a RET Prparations Initialisation du compteur Opration rpter Dcrmentation de b, et, si b0, saut relatif de 3d car : 0109h (adresse de linstruction suivante) -3d = 0106h, et -3d = FDh. Sortie de la boucle Fin Commentaire

Importance de l'adresse de dpart


Reprenons le premier programme de ce chapitre : Adresse (hexa) 0100 0102 0104 0105 0106 Code (hexa) 3E 26 16 1E 82 57 C9 Mnmonique LD a,26h LD d,1Eh ADD a,d LD d,a RET Commentaire

Supposons que ce programme soit excut non pas par CALL 0100h, mais par CALL 0101h. Le contenu de ladresse 0101h est alors interprt comme une instruction. 26h est alors interprt comme LD h,n. Le n est pris sur ladresse suivante (0102h), qui contient 16h. Le Z80 ralise alors LD h,16h. La prochaine instruction est donc ladresse 0103h : 1Eh ralise lopration LD e,n. En loccurrence, puisque 0104h contient 82h, le Z80 ralise LD e,82h. La prochaine instruction est donc ladresse 0105h : 57h ralise lopration LD d,a. La prochaine instruction est donc ladresse 0106h : C9h ralise lopration RET. Les mmes codes opration, vus partir dune adresse lgrement dcale, ralisent donc le programme suivant, qui na rien voir avec le prcdent et ne sert dailleurs rien : Le langage machine, lassembleur Page 7

Adresse (hexa) 0101 0103 0105 0106

Code (hexa) 26 16 1E 82 57 C9

Mnmonique LD h,16h LD e,82h LD d,a RET

Commentaire

On voit donc deux choses : Un octet lambda en RAM nest pas a priori oprateur ou oprande , programme ou donne . Ce nest que ladresse partir de laquelle un programme est appel qui dtermine ltat oprateur ou oprande des octets qui suivent. Le dcalage dun seul octet fait perdre toute signification un programme.

DESSINONS Affichage d'un pixel sur l'cran


Voyons maintenant, de manire simplifie, comment clairer sur l'cran un pixel donn. Supposons que nous ayons une carte graphique ayant les caractristiques suivantes : dfinition graphique = 256 pixels horizontaux 192 pixels verticaux en 256 couleurs. le "plan" de l'cran se situe directement en RAM, partir de l'adresse 1000h (par exemple). Il commence en haut gauche de lcran. Dans cette plage de la RAM, le contenu de chaque adresse spcifie la couleur afficher, chacune des 256 couleurs possibles tant dfinie au sein dune palette (qui prcise les 3 composantes RGB associes chaque code couleur). Par convention, nous supposerons que, dans cette palette, la couleur 0d soit le noir (chaque composante RGB 0), la couleur 1d soit le blanc (chaque composante RGB 255d). Voici un exemple de palette (ici stocke une adresse que nous appelons PALETTE) : Code couleur (hexa) 00 01 02 03 04 05 06 07 08 09 0A FF Composante rouge (dcimal) PALETTE 0 255 PALETTE + 01h3 64 PALETTE + 02h3 127 PALETTE + 03h3 192 PALETTE + 04h3 255 PALETTE + 05h3 255 PALETTE + 06h3 127 PALETTE + 07h3 255 PALETTE + 08h3 0 PALETTE + 09h3 255 PALETTE + 0Ah3 114 PALETTE + FFh3 Adresse Composante vert (dcimal) 0 255 64 127 192 0 0 0 255 255 127 73 Composante bleu (dcimal) 0 255 64 127 192 0 255 127 0 255 0 10 Couleur obtenue noir blanc gris fonc gris gris clair rouge rose violet jaune bleu ciel orange brun

Le tableau suivant rcapitule ladresse hexadcimale de chaque pixel (en 256 couleurs, 1 pixel = 1 octet, donc 1 pixel = 1 adresse) en fonction de sa position sur lcran (imaginez que ce tableau soit pos sur lcran) :

Le langage machine, lassembleur

Page 8

Haut de lcran

Gauche de lcran 1000 1100 CE00 CF00

1001 1101 CE01 CF01

10FE 11FE CEFE CFFE

Droite de lcran 10FF 11FF CEFF CFFF

Bas de lcran

Sur un pixel donn


Pour colorer un pixel, il suffit dinscrire la valeur de la couleur dsire dans son adresse en RAM. Par exemple, pour mettre en blanc le 3me pixel en partant de la gauche de la 2me ligne en partant du haut (leur principe tant dsormais bien compris si, si ! -, les codes opration ne sont plus affichs) : Adresse (hexa) 0000 0003 0005 Mnmonique LD HL,1102h LD (HL), 1d RET Commentaire Met ladresse du pixel modifier dans HL Inscrit le code couleur du blanc dans la case mmoire dadresse HL

Pour teindre ce pixel, il suffit de lui donner la mme couleur que celle de ses voisins. En supposant quils soient noirs : Adresse (hexa) 0000 0003 0005 Mnmonique LD HL,1102h LD (HL), 0d RET Commentaire Met ladresse du pixel modifier dans HL Inscrit le code couleur du noir dans la case mmoire dadresse HL

Sur un pixel quelconque


Les sous-programmes prcdents ne seront pas souvent utiles : seulement quand on veut blanchir ou noircir le 3me pixel en partant de la gauche de la 2me ligne. Il serait plus pratique dcrire un sous-programme allant inscrire le code couleur donn C ladresse correspondant au Xme pixel en partant de la gauche de la Yme ligne (X pouvant tre choisi entre 0 et 255 compris, Y entre 0 et 191 compris). Voici comment faire : On fixe trois octets de la RAM la fonction suivante : - Le premier (choisissons loctet dadresse D000h, juste aprs la RAM vido) est destin contenir le code couleur C - Le second (D001h) est destin contenir la valeur X - Le troisime (D002h) est destin contenir la valeur Y. A partir du quatrime octet, un sous-programme calcule ladresse correspondant cet octet (1000h+X+256dY), et y inscrit C. Voici le sous-programme :

Le langage machine, lassembleur

Page 9

Adresse (hexa) D000 D001 D002 D003

Mnmonique NOP NOP NOP PUSH hl

Commentaire Cet octet est rserv la donne C Cet octet est rserv la donne X Cet octet est rserv la donne Y Ce sous-programme allant utiliser le registre hl et ne sachant pas si le programme appelant lutilise, on le sauvegarde dans la pile, pour le rcuprer avant le retour au programme appelant. Charge Y dans a Ajoute 10h a Charge a (cest--dire Y+10h) dans h. Ainsi, h ayant un poids de 256d, hl contient bien (10h+Y)100h = 1000h+256dY Charge X dans a Charge a (cest--dire X) dans l. Ainsi, hl contient bien 1000h+X+256dY Charge C dans a Inscrit a dans loctet dadresse hl, cest--dire C en X-Y. On rcupre la valeur quavait hl lors de lappel par le programme appelant. Ainsi, pour ce dernier, la valeur de hl na pas chang (peuttre lutilise-t-il). Il ny a pas dincidence sur la commande RET suivante, car le PUSH/POP est ralis dans le mme sous-programme.

D004 D007 D009 D00A D00D D00E D011 D012

LD a,(D002h) ADD a,10h LD h,a LD a,(D001h) LD l,a LD a,(D000h) LD (hl),a POP hl

D013

RET

En maintenant ce sous-programme en mmoire, le travail consistant blanchir le 3me pixel en partant de la gauche de la 2me ligne consisterait en : Adresse (hexa) 0000 0002 0005 0007 000A 000C 000F Mnmonique LD a,1d LD (D000h),a LD a,2d LD (D001h),a LD a,1d LD (D002h),a CALL D003h Commentaire Charge la couleur dans a Linscrit en D000h Charge X dans a (X part de 0 pour le 1er pixel) Linscrit en D000h Charge Y dans a (Y part de 0 pour la 1re ligne) Linscrit en D000h Appelle le sous-programme. Cest le fait que ladresse dappel soit D003h (et non D000h) qui fait que les octets D000h D002h sont des donnes, et non du programme : CALL D000h na aucun sens. Grce au PUSH hl / POP hl du sousprogramme, la valeur de hl est conserve, ce qui serait obligatoire si le prsent programme lutilisait.

0012

RET

Cette mthode na pas le mrite dtre plus courte, mais de permettre de paramtrer entirement quel pixel on souhaite colorer, et en quelle couleur, ce que nous allons utiliser outrance. Pour des raisons mnmotechniques, nous appellerons dsormais PIXEL ladresse D003h. Il sagit dune simple convention entre nous : lorsque nous verrons ladresse PIXEL, il faudra comprendre D003h. De mme, lorsque nous verrons ladresse PIXEL-3, il faudra comprendre D000h, etc Les programmes dassemblage grent trs bien ce type de convention.

Affichage dun motif


Le langage machine, lassembleur Page 10

Supposons que nous voulions afficher une petite voiture en X-Y. Voici la voiture (il suffit dy croire : en regardant le schma 10 mtres de distance, on reconnat presque une affreuse limousine amricaine) : Origine Colonne Colonne Colonne Colonne Colonne Colonne +1 +2 +3 +4 +5 +6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Origine Ligne+1 Ligne+2 Ligne+3 Ligne+4

Chaque pixel est arbitrairement identifi par un numro. Rcapitulons la position de chaque pixel traiter partir de lorigine dfinie qui sera la coordonne X-Y de la voiture (le gris clair correspondant au code couleur 4d dans notre palette) : N pixel 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Dcalage horizontal 3 4 5 2 3 4 5 0 1 2 3 4 5 6 0 1 2 3 4 5 6 1 5 Dcalage vertical 0 0 0 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 Couleur 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Lide est de lire les dcalages horizontal et vertical du point 1 les ajouter respectivement X et Y lire sa couleur appeler PIXEL recommencer avec le point suivant et ainsi de suite jusquau dernier Il faut savoir combien de point il faut traiter. Pour cela, nous allons inscrire ces donnes partir dune adresse (choisissons D020h) que nous appellerons VOITURE, de la mme manire que nous avions dfini PIXEL. La mmoire contiendra donc les donnes suivantes : Adresse VOITURE VOITURE + 1 VOITURE + 2 VOITURE + 3 VOITURE + 4 Libell du contenu Nombre de points traiter Dcalage horizontal du point 1 Dcalage vertical du point 1 Couleur du point 1 Dcalage horizontal du point 2 Contenu 23 3 0 0 4

Le langage machine, lassembleur

Page 11

VOITURE + 5 VOITURE + 6 VOITURE + 7 VOITURE + 8 VOITURE + 9 VOITURE + 10 VOITURE + 11 VOITURE + 12 VOITURE + 13 VOITURE + 14 VOITURE + 15 VOITURE + 67 VOITURE + 68 VOITURE + 69

Dcalage vertical du point 2 Couleur du point 2 Dcalage horizontal du point 3 Dcalage vertical du point 3 Couleur du point 3 Dcalage horizontal du point 4 Dcalage vertical du point 4 Couleur du point 4 Dcalage horizontal du point 5 Dcalage vertical du point 5 Couleur du point 5 Dcalage horizontal du point 23 Dcalage vertical du point 1 Couleur du point 1

0 0 5 0 0 2 1 0 3 1 4 5 4 0

Ainsi, le petit programme suivant va afficher nimporte quel motif enregistr sous cette forme, nimporte quel endroit (de mme que prcdemment, nous nommerons ladresse de dpart MOTIF) : Adresse (hexa) MOTIF-4 MOTIF-3 MOTIF-2 MOTIF-1 MOTIF Mnmonique NOP NOP NOP NOP PUSH hl PUSH bc Commentaire Sert inscrire la valeur de X o il faut dessiner le motif Sert inscrire la valeur de Y o il faut dessiner le motif Sert inscrire loctet de poids fort de ladresse du motif dessiner (ici, le programme appelant inscrira loctet de poids fort de VOITURE) Sert inscrire loctet de poids faible de ladresse du motif dessiner Ce sous-programme utilisant hl, il sauvegarde hl pour le programme appelant Idem pour bc (le registre bc nest pas utilis en tant que tel, mais b est utilis, et il nexiste pas dinstruction PUSH b : qui peut le plus peut le moins) Idem pour de Inscrit dans hl ladresse VOITURE du motif dessiner Inscrit dans a le contenu de ladresse VOITURE, cest--dire nombre de points traiter Lenregistre dans b (compteur de DJNZ) Donnes

Sauvegarde des registres

PUSH de LD hl,(MOTIF-2) LD a,(hl) LD b,a

Dtermination du nombre de points

Le langage machine, lassembleur

Page 12

Adresse (hexa) BOUCLE1

Mnmonique INC hl LD a,(MOTIF-4) LD d,a LD a,(hl) ADD a,d LD (PIXEL-2),a INC hl LD a,(MOTIF-3) LD d,a LD a,(hl) ADD a,d LD (PIXEL-1),a INC hl LD a,(hl) LD (PIXEL-1),a CALL PIXEL DJNZ BOUCLE1 POP de POP bc POP hl RET

Commentaire Incrmente hl, pour passer ladresse (dcalage horizontal) Inscrit X dans a Enregistre dans d Inscrit le dcalage dans a Somme X et le dcalage Inscrit le rsultat dans le X de PIXEL Incrmente hl, pour passer ladresse (dcalage vertical) Inscrit Y dans a Enregistre dans d Inscrit le dcalage dans a Somme Y et le dcalage Inscrit le rsultat dans le Y de PIXEL Incrmente hl, pour passer ladresse (couleur) Inscrit la couleur dans a Inscrit la couleur dans le C de PIXEL Dessine le point en cours Passe au point suivant, jusquau (dtermin par la valeur de b) suivante Dtermination de labscisse du point en cours dans le motif

suivante Dtermination de lordonne du point en cours dans le motif

suivante Dtermination de la couleur du point en cours dans le motif

dernier Prochain pixel Restaure les registres pour le programme appelant

Le programme suivant permet dexploiter ce sous-programme. Pour dessiner la voiture en X=45d, Y=68d : Adresse (hexa) 0000 0002 0005 0007 000A 000D 0010 0013 Mnmonique LD a, 45d LD (MOTIF-4),a LD a, 68d LD (MOTIF-3),a LD hl,VOITURE LD (MOTIF-2),hl CALL MOTIF RET Commentaire Vise ladresse MOTIF-4 Pour y inscrire labscisse du motif Vise ladresse MOTIF-3 Pour y inscrire lordonne du motif Vise ladresse MOTIF-2 Pour y inscrire ladresse du motif Dessine le motif Fin

Animation
Essai
Dessiner une voiture, mme moche, cest bien, mais la faire avancer cest mieux ! Pour cela, nous allons appliquer le principe du cinma : afficher successivement des images dcales de la voiture, afin de donner lillusion de mouvement Il sagit de la dessiner des endroits successifs et voisins, par exemple : X=45d Y=68d, puis X=44d Y=68d, puis X=43d Y=68d, puis X=42d Y=68d, puis X=41d Y=68d, puis X=40d Y=68d, etc Ceci nest quune approximation, car une telle opration prsenterait le rsultat suivant (dtail de lcran) : Dessin en X=45d Y=68d :

Le langage machine, lassembleur

Page 13

Valeur de X Y=68d Y=68d Y=68d Y=68d Y=68d

40d

41d

42d

43d

44d

45d

46d

47d 4 10 17

8 15

9 16 22

48d 1 5 11 18

49d 2 6 12 19

50d 3 7 13 20 23

51d

14 21

Puis dessin en X=44d Y=68d : Valeur de X 40d 41d Y=68d Y=68d Y=68d Y=68d Y=68d

42d

43d

44d

45d

46d 4 10 17

8 15

9 16 22

47d 1 5 11 18

48d 2 6 12 19

49d 3 7 13 20 23

50d

51d

14 21

On constate que le dessin laisse une trace : en effet, le pixel (par exemple) X=50d Y=68d a t noirci lors de lopration prcdente, mais na pas t reblanchi dans la prsente opration. Si on ne provoque pas ce reblanchiement , il na aucune raison de se raliser tout seul (loctet correspondant en mmoire contient toujours le mme code couleur). Pour illustration, la suite des oprations serait la suivante : Dessin en X=43d Y=68d : Valeur de X Y=68d Y=68d Y=68d Y=68d Y=68d 40d 41d 42d 43d 44d 45d 4 10 17 46d 1 5 11 18 47d 2 6 12 19 48d 3 7 13 20 23 49d 50d 51d

8 15

9 16 22

14 21

Etc, jusquen X=40d Y=68d par exemple : Valeur de X Y=68d Y=68d Y=68d Y=68d Y=68d 40d 41d 42d 4 10 17 43d 1 5 11 18 44d 2 6 12 19 45d 3 7 13 20 23 46d 47d 48d 49d 50d 51d

8 15

9 16 22

14 21

En effet, nous navons pas effac larrire de la voiture avant chaque affichage de la nouvelle position. Nous allons prsenter ici deux possibilits pour le faire.

Premire solution
Une premire solution consiste inclure des bords blancs la voiture : Origine Colonne Colonne Colonne Colonne Colonne Colonne Colonne Colonne +1 +2 +3 +4 +5 +6 +7 +8 24 25 26 42 1 2 3 27 40 41 4 5 6 7 28 39 8 9 10 11 12 13 14 29 38 15 16 17 18 19 20 21 30 37 22 35 34 33 23 31 36 32

Origine Ligne+1 Ligne+2 Ligne+3 Ligne+4 Ligne+5 Ligne+6

Cela se ralise en compltant le tableau VOITURE :

Le langage machine, lassembleur

Page 14

Adresse VOITURE VOITURE + 1 VOITURE + 69 VOITURE + 70 VOITURE + 71 VOITURE + 72 VOITURE + 124 VOITURE + 125 VOITURE + 126

Libell du contenu Contenu Nombre de points traiter 42 Idem prcdemment, en tenant compte du changement dorigine (+1 pour chaque dcalage horizontal et chaque dcalage vertical) Dcalage horizontal du point 24 4 Dcalage vertical du point 24 0 Couleur du point 24 1 Etc Dcalage horizontal du point 42 3 Dcalage vertical du point 42 1 Couleur du point 42 1

Cet exemple ajoute des bords blancs dans les quatre directions (gauche, droite, haut, bas), en prvision de dplacements dans les directions opposes, afin deffacer la trane. Dans le cas du dplacement prcdent (de droite gauche), les points 27 31 et 35 auraient permis dempcher la trane en reblanchissant les pixels du dessin prcdent. Si on prvoit des dplacements dans huit directions (les quatre prcdentes plus leurs combinaisons, comme en haut droite ), il faut ajouter des bords de coin (43 53) : Origine Colonne Colonne Colonne Colonne Colonne Colonne Colonne Colonne +1 +2 +3 +4 +5 +6 +7 +8 43 24 25 26 44 53 42 1 2 3 27 52 40 41 4 5 6 7 28 45 39 8 9 10 11 12 13 14 29 38 15 16 17 18 19 20 21 30 51 37 22 35 34 33 23 31 46 50 36 49 48 32 47

Origine Ligne+1 Ligne+2 Ligne+3 Ligne+4 Ligne+5 Ligne+6

Lavantage de la mthode est sa simplicit. Son inconvnient est quelle suppose que lobjet se dplace sur un fond blanc (ou tout au moins uni, si on change la couleur blanche du bord pour la couleur de fond), ce qui est rarement le cas.

Deuxime solution
Reprenons la premire voiture : Origine Colonne Colonne Colonne Colonne Colonne Colonne +1 +2 +3 +4 +5 +6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Origine Ligne+1 Ligne+2 Ligne+3 Ligne+4

Pour permettre une animation sur un fond quelconque (notamment pas ncessairement uni), il est ncessaire denregistrer celui-ci, aux endroits o nous allons modifier les pixels en dessinant notre voiture. Il sagit donc de faire le travail inverse du programme MOTIF : passer chaque position pointe par le tableau VOITURE, mais au lieu de copier le code couleur dans le pixel correspondant de lcran, il sagit de lire le pixel sur lcran pour lenregistrer en mmoire vive, dans une structure du mme type que VOITURE que lon utilisera par la suite dans le programme MOTIF pour recoller le fond originel la place de la voiture. Nous appellerons cette structure FOND, et le programme inverse de MOTIF, ENR_FOND (pour ENREGISTRER_FOND ).

Le langage machine, lassembleur

Page 15

Situation initiale. Lcran (cest--dire la mmoire vido situe en RAM) contient une image, la RAM contient la dfinition dun dessin partir de ladresse VOITURE (ce que, par simplicit de vocabulaire, nous appelons le tableau VOITURE ). Nous devons dabord crer la structure FOND, grce un programme CREE_FOND. Ici, par soucis de lisibilit, le dessin est volontairement grossi. 2me image : ENR_FOND enregistre, ladresse FOND, les pixels de la mmoire vido que lon prvoit dcraser par le programme MOTIF affichant VOITURE. 3me image : MOTIF affiche VOITURE. 4me image : MOTIF affiche FOND, rtablissant ainsi laffichage initial. Nous devons donc crer deux programmes : CREE_FOND : copie VOITURE vers FOND, afin de bnficier de sa structure et des donnes que nous conserverons (en fait, nous nen modifierons que les codes couleurs). Cette tape sera articule autour dune instruction LDIR (copie de blocs mmoire). ENR_FOND : passe en revue chaque position indique par FOND. Pour chacune dentre elles, lit le code couleur sur lcran et lenregistre comme code couleur dans FOND. Lanimation consiste, aprs avoir utilis CREE_FOND et pour chaque position successive donner la voiture dans lanimation, en : appeler ENR_FOND appeler MOTIF, en indiquant VOITURE comme adresse de motif attendre un certain temps appeler MOTIF, en indiquant FOND comme adresse de motif incrmenter la position traiter le coup suivant Lattente a pour but de laisser la voiture affiche un temps suffisant pour que la rtine la voie. Cela peut tre constitu par un rel programme dattente, ou bien naturellement par dautres calculs que le programme doit raliser de toutes manires pour dautres fonctions (gestion dautres animations, lectures / critures sur le disque dur ou en mmoire, dtection des touches utilises du clavier, etc). Voici une solution possible du programme CREE_FOND : Adresse (hexa) -4 -3 -2 Mnmonique NOP NOP NOP Commentaire Sert inscrire loctet de poids fort de ladresse du motif copier (ici, le programme appelant inscrira loctet de poids fort de VOITURE) Sert inscrire loctet de poids faible de ladresse du motif copier Sert inscrire loctet de poids fort de ladresse FOND o le MOTIF sera copi (ici, le programme appelant inscrira loctet de poids fort de FOND)

1re image :

Le langage machine, lassembleur

Page 16

Adresse (hexa) -1 CREE_FOND

Mnmonique NOP

Commentaire

Sert inscrire loctet de poids faible de ladresse FOND o le MOTIF sera copi PUSH hl Ce sous-programme utilisant hl, sauvegarde hl Sauvegarde des registres pour le programme appelant PUSH bc Idem pour bc PUSH de Idem pour de LD hl,(CREE_FOND hl pointe sur VOITURE -4) LD c,(hl) Inscrit le nombre de points enregistrs par Calcule la taille, en octets, du VOITURE (signification du premier octet du tableau VOITURE (nombre tableau VOITURE) dans c. doctets copier, inscrire dans LD b,0 Ainsi, bc contient (hl) bc pour linstruction LDIR) LD l,c Avec linstruction suivante, ralise LD hl,bc LD h,0 ADD hl,bc Ralise hl = 2bc ADD hl,bc Ralise hl = 3bc INC hl Ralise hl = 3bc + 1 LD b,h Avec linstruction suivante, ralise LD bc,hl LD c,l Ainsi, bc contient le nombre doctets du tableau VOITURE LD hl,(CREE_FOND hl pointe sur VOITURE, source de la copie Adresse source de la copie -4) raliser. LD de,(CREE_FOND de pointe sur FOND, destination de la copie Adresse destination de la copie -2) raliser. LDIR Ralise la copie de bc octets depuis VOITURE Copie les bc octets de vers FOND. VOITURE depuis hl (VOITURE) vers de (FOND) POP de Restaure les registres POP bc pour le programme appelant POP hl RET

Voici une solution possible du programme ENR_FOND (avec un sous-programme LIT_PIXEL qui retourne le code couleur du point X,Y de la mmoire vido, dtaill aprs) : Adresse (hexa) -4 Mnmonique NOP Commentaire

Sert inscrire la valeur de X o il est prvu de Donnes dessiner le motif -3 NOP Sert inscrire la valeur de Y o il est prvu de dessiner le motif -2 NOP Sert inscrire loctet de poids fort de ladresse o le fond sera enregistr (ici, le programme appelant inscrira loctet de poids fort de FOND) -1 NOP Sert inscrire loctet de poids faible de ladresse o le fond sera enregistr ENR_FOND PUSH hl Ce sous-programme utilisant hl, sauvegarde hl Sauvegarde des registres pour le programme appelant PUSH bc Idem pour bc PUSH de Idem pour de LD hl,(ENR_FOND - Inscrit dans hl ladresse FOND Dtermination du nombre de 2) points LD a,(hl) Inscrit dans a le contenu de ladresse FOND, cest--dire nombre de points traiter LD b,a Lenregistre dans b (compteur de DJNZ) Le langage machine, lassembleur Page 17

Adresse (hexa) BOUCLE2

Mnmonique INC hl

Commentaire

Incrmente hl, pour passer ladresse suivante Dtermination de labscisse du (dcalage horizontal) point en cours dans le motif LD a,(ENR_FOND - Inscrit X dans a 4) LD d,a Enregistre X dans d LD a,(hl) Inscrit le dcalage dans a ADD a,d Somme X et le dcalage LD (LIT_PIXEL-2),a Inscrit le rsultat dans le X de LIT_PIXEL INC hl Incrmente hl, pour passer ladresse suivante Dtermination de lordonne du (dcalage vertical) point en cours dans le motif LD a,(ENR_FOND - Inscrit Y dans a 3) LD d,a Enregistre Y dans d LD a,(hl) Inscrit le dcalage dans a ADD a,d Somme Y et le dcalage LD (LIT_PIXEL-1),a Inscrit le rsultat dans le Y de LIT_PIXEL INC hl Incrmente hl, pour passer ladresse suivante Enregistrement de la couleur du (couleur) point en cours dans le motif CALL LIT_PIXEL Inscrit le code couleur du pixel point dans a (voir ci-dessous) LD (hl),a Linscrit alors dans le tableau FOND. DJNZ BOUCLE2 Passe au point suivant, jusquau dernier Pixel suivant (dtermin par la valeur de b) POP de Restaure les registres POP bc pour le programme appelant POP hl RET

Comment modifier lgrement PIXEL pour quil ralise la fonction LIT_PIXEL quon attend de lui ? Voici la rponse : Adresse (hexa) -2 -1 LIT_PIXEL Mnmonique NOP NOP PUSH hl LD a,(LIT_PIXEL-1) ADD a,10h LD h,a LD a,(LIT_PIXEL-2) LD l,a LD a,(hl) POP hl RET Commentaire Cet octet est rserv la donne X Cet octet est rserv la donne Y Idem PIXEL

Inscrit le code couleur du pixel point dans a Idem PIXEL

Dsormais, nous avons tous les outils pour raliser notre animation : Causer du temps de chaque instruction################ CREE_FOND (VOITURE,FOND) Initialise X Dbut de boucle : ENR_FOND (X,Y,FOND) MOTIF (VOITURE) Attente MOTIF (FOND) X <- X+1 Retour boucle

Le langage machine, lassembleur

Page 18

Adresse (hexa) -6

Mnmonique NOP

Commentaire

Sert inscrire la valeur de Xd de dpart pour Donnes lanimation -5 NOP Sert inscrire la valeur de Xf de fin pour lanimation -4 NOP Sert inscrire loctet de poids fort de ladresse VOITURE -3 NOP Sert inscrire loctet de poids faible de ladresse VOITURE -2 NOP Sert inscrire loctet de poids fort de ladresse FOND -1 NOP Sert inscrire loctet de poids faible de ladresse FOND ANIMATIO PUSH hl Ce sous-programme utilisant hl, sauvegarde hl Sauvegarde des registres N pour le programme appelant PUSH bc Idem pour bc PUSH de Idem pour de LD hl contient ladresse du tableau FOND Initialisation des donnes pour hl,(ANIMATION-2) lensemble des sousprogrammes LD (CREE_FOND- Ladresse de FOND est copie comme donne 2),hl du sous-programme CREE_FOND LD (ENR_FOND- Ladresse de FOND est copie comme donne 2),hl du sous-programme ENR_FOND LD hl contient ladresse du tableau VOITURE hl,(ANIMATION-4) LD (CREE_FOND- Ladresse de VOITURE est copie comme 2),hl donne du sous-programme CREE_FOND LD (MOTIF-2),hl Ladresse de VOITURE est copie comme donne du sous-programme MOTIF LD a,100d On fixe arbitrairement la valeur de Y 100d LD (ENR_FOND-3),a Quon inscrit en donne fixe de ENR_FOND LD (MOTIF-3),a et de MOTIF CALL CREE_FOND Cre la structure FOND LD a,(ANIMATION- Charge le Xd de dbut dans a Calcule le nombre de fois o la 6) boucle danimation devra tre LD b,a excute = Xf - Xd LD a,(ANIMATION- Charge le Xf de fin dans a 5) SUB a,b Inscrit Xf - Xd dans a LD b,a Transfre le rsultat dans b, car b est le registre de contrle de la future boucle DJNZ. LD a,(ANIMATION- Recharge le Xd de dbut dans a Initialise la premire position 6) de X = Xd

Le langage machine, lassembleur

Page 19

Adresse (hexa) BOUCLE3

Mnmonique

Commentaire Enregistre le fond.

BOUCLE4

LD (ENR_FOND-4),a Transmets la valeur en cours de X au sousprogramme ENR_FOND CALL ENR_FOND Enregistre le fond dcran la position X en cours LD hl,VOITURE Inscrit ladresse VOITURE dans hl LD (MOTIF-2),hl Inscrit ladresse VOITURE ladresse MOTIF-2 CALL MOTIF Dessine la voiture la position X en cours. LD hl,5555d Initialise hl 5555d DEC hl Dcrmente hl. Le drapeau Z est 1 si le rsultat est nul, Z = 0 sinon. JR NZ BOUCLE4 LD hl,FOND LD (MOTIF-2),hl CALL MOTIF INC a DJNZ BOUCLE3 POP de POP bc POP hl RET Retourne en BOUCLE4 si Z = 0.

Dessine la voiture

Inscrit ladresse FOND dans hl Inscrit ladresse FOND ladresse MOTIF-2 Raffiche le fond la position X en cours. Incrmente a Donne X la valeur suivante Dcrmente b, et retourne en BOUCLE3 si b Passe au traitement du pixel est non nul. suivant jusquau dernier (dtermin par la valeur de b). Restaure les registres pour le programme appelant Retourne lappelant.

Boucle dattente Pour laisser le temps la voiture dtre affiche assez longtemps pour tre vue. Cette boucle ne fait rien dautre que dtre excute 5555d fois Raffiche le fond

Boucle dattente : dans le Z80, LD hl,nn utilise 10 cycles dhorloge DEC hl utilise 6 cycles dhorloge JR NZ n utilise 12 cycles dhorloge quand le branchement a lieu, 7 sinon. Ainsi, lensemble de la boucle utilise 10 + 5555 (6+12) (12-7) 100 000 cycles dhorloge. Avec un Z80 travaillant 1 MHz, on force ici une attente de 0,1 seconde, permettant davoir un temps daffichage de la voiture suffisant pour quelle soit vue par la rtine, et en tous cas bien plus important que le temps entre son effacement et son affichage la position suivante.

LECTURE DES TOUCHES DU CLAVIER


########### Commander le dplacement de la voiture en fonction de la touche enfonce. Genre : Ca serait pas mal si la voiture se dplaait en fonction des touches quon presse (flches gauche ou droite). Afficher la voiture Attendre quune touche soit presse (attente pour rendre la voiture visible) Effacer la voiture Afficher la nouvelle voiture Attendre que la touche ne soit plus presse

ECRIVONS Affichage d'un caractre


Le code ASCII

Affichage d'un texte CALCUL DU TEMPS DE TRAITEMENT#


Le langage machine, lassembleur Page 20

Sous-programmes
#RAM = programme parler de SP#

La pile

MACRO-ASSEMBLAGE

Le langage machine, lassembleur

Page 21

Das könnte Ihnen auch gefallen