************************* * un mini jeux: TRON * * par superCOCOHP * ************************* INTRODUCTION: Attention ne vous attendez pas a un super tron avec scolling differentiel etc... C'est juste un point qui bouge et vous perdez quand vous touchez un point noir(c'est mŠme un crime d'appeler ca un TRON). Pour cela j'ai fait un programme principal: TRON, avec deux sous routines: -EFFACE:qui efface l'‚cran et dessine le cadre -PUTPIXEL:qui prend en argumentl'absice et l'ordonn‚e d'un point pour le mettre en noir -TRON.RPL:qui assemble TRON et affiche le score(il ne sera pas comment‚, ceci n'etant pas un cour de ReuPleupLeu(ou RaPlapLa (comme vous voudrez))). NOUVELLE FORMULE: Je vais faire un nouveau truc plus sympas: ici je vais juste commenter le programme et je vais faire des petits fichiers sp‚cifique pour tous les petits problŠmes qu'on peut avoir en assembleur: -mettre un objet dans la pile -mettre des datas dans un programme ASM -tester le clavier -reserver un ‚cran... Comme ca si vous avez oubli‚ comment tester le clavier vous serez pas oblig‚s de regarder tous les cours pour trouver ou c'est que c'est marqu‚. TRON: Avant de commencer a analyser ce source quelques petits d‚tails sur son fonctionnement. D‚ja meme si ca vous parait long, c'est un programme hyper simple. Y a pas plus bateau. J'ai taper ca en moins d'une demi-heure et ca a march‚ du premier coup. Donc ne vous affol‚s pas en vous disant "Putain l'assembleur c'est trops long, il faut un ‚norme source pour faire un minuscule truc.". C'est faux. D‚ja ceci est un source relativement petit et de plus ca va tres vite a taper quand on sait ce qu'on veut faire. Si vous le comprenez bien vous devriez ˆtre capable de le r‚ecrire(sans regarder) en moins d'une heure. Et une heure pour faire un TRON aussi rapide en ASM, au niveau qualit‚ rendement, c'est quand mˆme mieux que d'avoir pass‚ une demi heure a le faire en ReuPleuPleu. Donc le fonctionnement est tres simple: on va se servir des 5 registre R0,R1,..,R4 de sauvegarde. -dans R0 on va mettre l'absice(au pixel prŠs:de 0 a 131) -dans R1 on va mettre l'ordonn‚(de 0 a 63) -dans R2 on va mettre ce qu'il faut ajouter a R0(absice) a chaque boucle: si vers la droite R2=1 si vers la gauche R2=FFFFF (quand on l'ajoute ca foit comme -1) si vers haut ou bas R2=0(on laisse l'absice identique, deplacement vertical) -dans R3 on va mettre ce qu'il faut ajouter a R1(ordonn‚) a chaque boucle: si vers le bas R3=1 si vers la haut R3=FFFFF (quand on l'ajoute ca foit comme -1) si vers gauch ou droite R3=0(deplacement horizontal) -dans R4 on met un compteur qui compte le nombre de point affich‚s(le score). Le testeur de touche (haut,bas,droite,gauche) ne modifiera que les valeurs de R2 et R3 changeant ainsi la direction du point: si touche bas appuy‚e: R2=0 R3=1 si touche haut appuy‚e: R2=0 R3=FFFFF si touche droite appuy‚e: R2=1 R3=0 si touche gauche appuy‚e: R2=FFFFF R3=0 Bon si vous regardez le source vous vous appercevez que ca se passe pas tout a fait comme ca parce qu'on ne peut pas charger directement des valeurs dans les registres de sauvegarde. On est oblig‚ de passer par C. Vous remarquerez aussi que on ne peut pas aller en diagonale en appuyant sur deux touches en meme temps. Je l'avais fait au depard mais cela fait bizarre parce que quand on lache les deux touches ca continue a aller en diagonale et ca fait NAZE. Bon on peut le faire pour que ca prenne l'orientation de la dernier touche appuy‚e mais ca alourdi le source qui est quand mŠme sens‚ etre simple. Voila le programme est maintenant simple: 1-on teste le clavier qui nous modifie eventuellement R2 ou R3 2-on teste la touche ON pour quitter 3-on fait R0=R0+R2(absice)(indirectement par C et par A) R1=R1+R3(ordonn‚) 4-on ecris ensuite le point de coordonn‚ R0,R1 avec la routine PUTPIXEL. cette routine nous renvoit -ST=1 si le pixel ‚tait deja noir(perdu) -ST=0 si le pixel ‚tait blanc 5-petite boucle d'attente(inutile en RPL) 6-incrementation du compteur 7-si ST=1 on se casse sinon on recommence Y en a t'il un qui soit assez bŠte pour ne pas avoir compris(ca peut pas exister). C'est le programme le plus con qu'on puisse faire. Ah oui au fait le magnifique bruit que l'on entend est du au fait que je fait OUT=C avec C=0??(quand je teste les touches) OUT=C avec C=FFF(quand je fait ON) pour envoyer du courant au buzzer il suffit de faire OUT=C avec C=800 (en binaire 1000 0000 0000 c'est la derniere ligne de sortie) pour le faire vibrer il faut a intervalles reguliers envoyer 0 et 1 sur la derniŠre ligne. Avec OUT=C(C=FFF) j'envois du courant sur toutes les lignes (binaire 1111 1111 1111). " 'PRO On merge le program de prologue(sauv les registres) !0-15 Notation des bits:de 0 a 15 !PC Notation PC INTOFF Coupe les interuptions ST=0 15 Ainsi que les s‚quences ON-C etc..(mŠme ON-A-F) GOSUB efface On efface l'‚cran et on trace le cadre LC 10,R0=C %absice coords de d‚pard 10,10 LC 10,R1=C %ordone LC 01,R2=C %inc abs Et direction droite(+1 en absice et +0 en ordonn‚e) LC 00,R3=C %inc ord C=0 A,R4=C %compteur Mise du compteur … 0 %******************* %voici le cerveau du % prog %******************* *main_boucle Label du d‚pard de la boucle GOSUB test_clavier On teste le clavier et on modifie R2 et R3 %teste ON LC FFF,GOSBVL 01EEC On charge FFF dans C et on fait OUT=C,C=IN ?CBIT=1 15,GOYES quitte (Le gosbvl le fait a une addresse paire) ensuite on teste le dernier bit de l'entr‚e(touche ON) %incr‚mente A=R0 Charge R0 dans A(absice) C=R2 Charge R2 dans C(incr‚ment absice) A=A+C B On effectue l'addition R0=A On sauve la nouvelle absice dans R0 A=R1 Idem pour R1 C=R3 Auquel on additionne R3 C=C+A B R1=C A=R0 On remet R0 dans A(on a donc C=R1 et A=R0) GOSUB put_pixel On allume et on teste le pixel de coordonn‚e A,C GOSUB wait On attend un petit peu GOSUB inc_compteur On incr‚mente le compteur ?ST=0 0 On teste le drapeau 0(mis peut etre a 1 par putpixel) GOYES main_boucle S'il est a 0 on recommence la boucle *quitte Voila c'est fini(snif) C=DAT1 A On lit l'adresse de l'objet au niveau 1 D1=C On la fait passer dans D1 D1=D1+ 10 On additionne 10 quartets(->sauter prologue et taille) C=R4 On charge le compteur dans C DAT1=C A On l'ecris a l'adresse point‚e par D1 ST=1 15 On autorise les ON-C etc.. INTON On remet les interuptions 'ENDE Reload les registres et rend la main au systeme *wait La boucle d'attente LC 008FF (C=8FF)Voici le compteur(on fait 2304 fois la boucle) *wait_boucle C=C-1 A sans commentaires GONC wait_boucle si le champs n'est pas d‚pass‚(C=0 A et on fait C=C-1) RTN on saute au debut sinon RTN(=return comme en BASIC) *inc_compteur Incr‚menter le compteur R4(par l'interm‚diaire de C) C=R4 C=C+1 A Sans commentaires R4=C RTN Return *test_clavier Voice la routine quui teste le clavier *gauche LC 004,GOSBVL 01EEC On charge 004 dans C et on fait OUT=C,C=IN(le GOSBVL) ?CBIT=0 3,GOYES droite Si le 4eme bit est a 0 on continue(notation 0-15) LC FF,R2=C Sinon R2=FF(en fait c'est -1) LC 00,R3=C Et R3=0 *droite LC 004,GOSBVL 01EEC Toujours la mŠme sortie ?CBIT=0 1,GOYES haut On teste maintenant le 2eme bit LC 01,R2=C R2=1 (vers la droite:absice+1 et ordonn‚e +0) LC 00,R3=C R3=0 *haut LC 008,GOSBVL 01EEC Bon c'est la meme chose ?CBIT=0 2,GOYES bas La table pour les touches est page 73 de voyage LC 00,R2=C +0 en absice (vers le haut) LC FF,R3=C -1 en ordonn‚e *bas LC 002,GOSBVL 01EEC ?CBIT=0 2,RTNYES si la touche "2" n'est pas appuy‚e on fait RTN(return) LC 00,R2=C +0 en absice (vers le bas LC 01,R3=C +1 en ordon‚e RTN return vers la main boucle 'PUTPIXEL merger la routine qui affiche et teste les pixels @" marque de fin indispensable a ASMFLASH EFFACE: Voice maintenant la routine qui efface l'ecran et met un cadre noire. Une ligne fait 34 cases(ou quartets). On va donc mŠttre la premiŠre en noire. Dans les suivantes il faut pas oublier de dessiner les cot‚s du cadre. Pour cela on met un 1 dans la premiŠre case de C(toute les autres a 0). Ca fera le bord gauche(souvenez vous que la premiŠre case est ‚crite en premier. Avec le premier bit de la premiŠre case a 1, ca fait un pixel en d‚but de ligne). Pour le cot‚ droit il faut alumer un pixel au 3eme bit de la 33eme cases en partant du d‚but de la ligne. Arriv‚ a la 33eme case de la ligne(on a d‚ja fait D0=D0+ 16 deux fois) le 3eme bit de A est mis a 1 et on ‚cris 2 cases. La derniŠre case ‚crite n'apparait pas a l'‚cran. A la fin on retrace une ligne noire. Tous les petits malin remarque alors l'int‚ret du GOSUB pour tracer une ligne noire: ca ‚vite de r‚‚crire deux fois la mŠme chose. %un bel ecran tout propre *efface D0= 7050E Addresse ou est l'addresse de l'ecran(sur 5 cases) A=DAT0 A On lit 5 cases D0=A On met l'addresse de l'‚cran courant dans D0 GOSUB noire On fait un GOSUB pour ‚crire une ligne noire LC 35 On charge 35h dans C(53 en decimal) D=C B On met cela dans D(champs B= les 2 premiŠres cases) C=0 W tous les quartets de C a 0(les 16 cases) LC 1 On charge 1 dans la premiŠre case *b_efface DAT0=C W On ‚cris 16 cases dans l'ecran(blanche sauf la 1) D0=D0+ 16 On passe au 16 suivantes A=0 W Toutes les cases de A a 0 DAT0=A W On ecris encore 16 cases(toutes blanches) D0=D0+ 16 On passe au 16 suivantes ABIT=1 2 On met le troisieme bit de A a 1 DAT0=A B On ecris encore 2 cases D0=D0+ 2 On passe ces deux cases D=D-1 B On d‚cr‚mente le compteur GONC b_efface Si champs B non d‚pass‚ on recommence GOSUB noire On trace une ligne noire(bas du cadre) RTN On retourne au programme principal *noire GOSUB pour tracer une ligne noire A=0 W tout les quatets de A … 0 A=A-1 W le champs W est d‚pass‚->tous les quartets a F DAT0=A W On ‚cris 16 cases D0=D0+ 16 On passe au 16 suivantes DAT0=A W On en r‚‚cris 16 D0=D0+ 16 La suite s'vous plait DAT0=A B Les 2 cases du bout de la ligne D0=D0+ 2 On les saute RTN Return: on retourne au GOSUB d'ou l'on est partit @" PUTPIXEL: Cette routine est ce qu'il y a de plus balaise dans tout le programme. La derniŠre fois on avait affich‚ un point, mais c'‚tait un point pr‚cis. Cette fois l'absice est dans A et l'ordonn‚e en C. Cette routine est de loin la plus compliqu‚e de tout le programme. On aurait pu faire un GOSBVL en ROM pour nous dessiner le point mais ca aurait ‚t‚ de la triche. Une ligne fait 34 cases. Pour se positionner au d‚but de la ligne d'ordon‚e C il va donc falloir ajouter a l'adresse de d‚but de l'‚cran C*34. Pour multiplier C par 34 on va d'abors le faire passer dans B pour le multiplier par 2, puis on le remet dans C. Ensuite on remultiplie B par 16(total dans B on a ordonn‚e*32). On ajoute ensuite B a C C=ordonn‚e*2+ordonn‚e*32 = ordonn‚e*34 L'instruction BSL A multiplie par 16 ou plutot d‚cale tous les quartets d'une case vers la gauche(cela met un 0 dans la premiere case: resultat comme nous somme en base 16 cela multiplie par 16 le nombre stoqu‚ dans B). Il faut ensuite avancer dans la ligne pour se positionner sur la case ou sera le point. Une case code pour 4 pixels. On met donc l'absice dans B que l'on divise par 4. On additionne cela a C et on obtient ainsi l'offset ‚cran pour le point. Offset signifie "distance par rapport a ... pour ...". Ici c'est la distance par rapport au d‚dut de l'‚cran pour le point(offset ‚cran du point). On lit ensuite l'addresse de d‚but de l'‚cran en 7050E(SX)(sur 5 cases) et on y additionne ordonn‚e*34+basice/4 que l'on acalcul‚ pr‚cedemment et qui est dans C. Ouf nous voila au positionn‚ dans l'‚cran. Le r‚sultat est mis dans D0. Il va maintenant falloir d‚terminer ou est le pixel dans le quartet(la case) point‚e par D0. C'est le role de la routine witch_pix (ceux qui sont pas d'accord avec mon anglais vont voir ailleurs si j'y suis). Les 2 premier Bits de A(absice) vont nous dire quel pixel c'est . On les a ‚limin‚s quand on a divis‚ par 4(il faut savoir que diviser par 2 ‚quivaut a d‚caler d'un bit vers la droite). Ce que l'on va faire est trŠs simple. On considŠre au d‚pard que ces deux bits sont a 0 et on le premier bit de C a 1(LC 01). Si ils sont effectivement a 0 il suffira d'‚crire C dans la case point‚ par D0. Resumons, voici lesvaleurs des deux premier BITS de A et le pixel(ou bit) qu'il faut allumer a l'‚cran. 00:premier bit du quatet point‚ par D0(ou la case) 01:second bit du quatet point‚ par D0 10:troisieme bit du quatet point‚ par D0 11:quatrieme bit du quatet point‚ par D0 Donc si ils sont a 0 c'est bon(on ecris C). Si le premier(?ABIT=0 1) bit n'est pas a 0 on va d‚caler la valeur qu'il y a dans C de 2 bits vers la gauche(car ca sera soit le 3eme soit le 4eme bit). Ensuite si le second est a 1 aussi on va red‚caler C d'un bit vers la gauche. Vous n'avez rien compris? Voici un tableau recapitulatif: 2 premier 1ere case de bits de A C(en binaire) 00 0001(pas de d‚calage) 01 0010(d‚cale d'une case) 10 0100(d‚cale de 2 cases) 11 1000(d‚cale de 3 cases(d'abord de 2 puis de 1) Voila maintenant il suffit d'‚crire la premiŠre case de C … l'addresse point‚e par D0. Cependant avant on lit ce qu'il y a dans cette case. Il ne faut pas que l'on‚fface les point qu'il pouvait d‚ja y avoir dans cette case. On va donc effectuer un OU logique entre C et A(dans A il y a l'ancien contenu de la case). Le OU va prendre A et va y rajouter les bits qui sont allum‚s dans C(ca va y mettre le pixel quoi). Ensuite on r‚‚cris A dans l'‚cran. Pour savoir si le point ‚tait d‚ja allum‚, on a sauver l'ancienne valeur du quartet point‚ par D0 dans B. On effectue alors un ET logique entre B et C. Le ET ne garde que les bits qui sont simultan‚ment allum‚s dans B et dans C. C ne contenait que des bits a 0 sauf 1(le pixel allum‚). Dans B si ce bit est ‚galement alum‚, il reste et B est diff‚rent de 0 sinon B=0. On positionne ensuite le drapeau suivant que B est egal ou pas a 0. SOURCE DE PUTPIXEL: "%abs en A,ord en C Comme c'est une routine qui peut reservir il vaut %A,B,C,D0 modifies mieux mettre ce que ca modifie en haut *put_pixel ST=0 0 le drapeau 0 a 0(par d‚fau le point est blanc) B=0 A 5 premiŠres cases de B a 0 B=C B on copie C dans B(deux premiere cases) B=B+B A on multiplie B par 2 C=B A on copie B dans C BSL A on multiplie B par 16(decalage d'une case a gauche) C=C+B A on additionne B a C Total sur la valeur de d‚pard:*34 B=0 A mise a 0 de B sur 5 cases B=A A on copie A(l'absice) dans B BSRB A On divise B par 2 BSRB A On redivise B par 2(au total B est divis‚ par 4) B=B+C A On additionne C a B(donne l'offset ‚cran) D0= 7050E Addresse ou est l'addresse de l'‚cran(sur 5 cases) C=DAT0 A on lit 5 cases dans C C=C+B A On additionne B a C(C=addresse ecran+offset point) D0=C On met le resultat dans D0 GOSUB witch_pix D‚termine lequel des quatres pixels point‚s par D0 sera l'heureux elu A=DAT0 B On lit 2 cases de l'‚cran B=A A On les sauve A=A!C B Le pixel est dans C donc on fait un OU logique DAT0=A B AprŠs ca on r‚‚cris le resultat a l'‚cran B=B&C A Si le pixel est aussi dans B alors B ca ne sera pas nul(c'est un ET logique) ?B=0 B on teste si B est a 0(pas de point) RTNYES si oui RETURN ST=1 0 sinon on met ST0 a 1(le drapeau 0) RTN return(come back) *witch_pix Lequel des quatres pixels LC 01 charge 01 dans C ?ABIT=0 1 teste si le 2eme BIT de A est a 0 GOYES pix1-2 si oui on saute en pix1-2 C=C+C A sinon on multiplie C par 2(on decale d'un bit) C=C+C A puis encore par 2(total multipli‚ par 4) *pix1-2 ?ABIT=0 0 on teste maintenantle premier bit de A RTNYES s'il est a 0 on effectue un return C=C+C A sinon on d‚cale encore C d'un BIT RTN return @" GX: Tous les heureux poss‚seur de GX me remplace 7050E par 8068D dans EFFACE et PUTPIXEL et ca marchera pareil. LA PILE: On a ecris un nombre dans un entier binaire dans la pile. Le fontionnement de la pile n'est pas compliqu‚ mais il est long. Il y aura une mini DOC sans source la dessus. CONCLUSION: Voila c'est fini(snif) on va se quitter. Pour ceux qui savent d‚ja bien programmer en ASM vous vous rendrez compte que ce source n'est pas g‚nialement concu. On pourait facilement r‚duire la taille par un choix judicieux de champs. Parfois des instruction sont lourdes (LC 00 au lieu de C=0 B) mais ca fait plus clair et est‚tique. De plus c'est de la programation bateau(sauf un peu pour PUTPIXEL). On peut faire beaucoups plus rapide, plus petit, plus structur‚. Le probleme est que parfois je me dis qu'il faut que je privilegie la taille(C=R0 sans champs prend 1.5pas alors qu'avec un champs cela en prend 3). De mŠme pour la plupard du temps le champs A cela prend 1 pas(1.5 avec les autres). Et des fois je privil‚gie la vitesse(champs les plus petits possible). Ne me faite donc pas trops de critique si je n'optimise pas mes sources. La priorit‚e numero 1 ‚tant qu'il soient comprehensibles. Si je l'optimisait il faudrait: -revoir tous les champs et les addapter -faire passer tous les GOSUB dans la boucle principale pour gagner de la place et du temps -utiliser le moins d'instruction possible. -se servir simutan‚ment du champs B et M pour ‚viter d'avoir a utiliser les registres de sauvegarde(ces champs ne se chevauchent pas). Si vous avez un problŠme avec vos source envoy‚ les moi. D'autre part s'il y en a qui veulent qu'on fasse des progs ensemble y a pas de problŠme. Moi je suis nul en dessin et en external(ca me fait chier). On peut se partager la partie ASM(hey faut bien que je fasse quelque chose quand mŠme). Moi je ferais bien un jeu de baston. Que vous ayez compris ou pas JE VEUX DES MESSAGES EN *CRS pour dire n'importe quoi(enfin pas trops d'obscenit‚s quand mŠme). Merci aux fidŠles de mes cours(par exemple a WOOD). Je mettrais a la fin de tous les prochains cours la listes des mecs actifs(qui participent en CRS par exemple). Si la gloire vous int‚resse???. Je leur filerais mŠme peut Štre des niveau(ca y est y a embouteillage, j'ai dit le mot magique). Allez see you on RTC ONE(48-70-10-29) votre RTC pr‚f‚r‚ et ne faites pas trops de memory clear.