Sponsors

FacebookTwitterGoogle Bookmarks

LANGAGE : Rexx est un langage qui existe depuis 1985, et son succès sur d’autres machines a tout naturellement provoqué le désir de le porter sur Amiga. Son introduction dans notre excellente machine date de 1987 et a été réalisée par W. S. Hawes qui s’est efforcé, le fait est remarquable, de coller le plus parfaitement possible à la définition de Rexx, de sorte que ceux qui connaissent Rexx ne seront pas dépaysés. !? &REXX LA VOIE RC bien le dire, à nul autre pareilles. En tant que langage de programmation. Arexx est utile à un large spectre d’utilisateurs. Il est à la fois très facile à apprendre, car s'apparentant au Basic, et très puissant. Toutefois, au lieu de viser à l'universalité, il est principalement orienté vers le traitement des caractères et très bien adapté comme langage de commandes. Les programmes de commandes sont fréquemment appelés "scripts" (ou. Plus techniquement, "macros") ; ils sont écrits dans un fichier de type texte et sont largement utilisés pour élargir l'ensemble des commandes prédéterminées d'un logiciel ou pour en personnaliser une application. Par contre, ses capacités mathématiques sont faibles et les graphiques inexistants. Que l'on se rassure toutefois, l'appel aux bibliothèques spécialisées pallie à cette apparente faiblesse. Nous verrons donc par la suite comment Arexx permet : Pendant quelques temps, Arexx n’a été l'apanage que de quelques spécialistes et d’amateurs avertis, juste le temps d’atteindre la version 1.15. Les hommages lui furent alors rendus, qui le placent désormais au rang des fonctions de base de l’Amiga 3000. Mais malgré son succès, dû à son intérêt, sa popularité n’a pas atteint, à notre sens, le niveau qu’elle devrait logiquement avoir. En inconditionnels d’ARexx, après l'avoir été de Rexx, nous développerons dans ces colonnes successivement : la présentation, l'intérêt, les modalités d’emploi et enfin l’utilisation de Arexx dans une présentation qui associera les règles théoriques et les exemples pratiques de façon à satisfaire tant lé débutant ou l'exploitant moyen, que l'exploitant le plus expérimenté de l'Amiga (du 500 au 3000) . Une ouverture enfin sera donnée au programmeur développeur qui ne saurait aujourd'hui réaliser un bon produit sans une inclusion de Arexx dans le fruit de ses travaux, utilitaire ou jeu !

Click image to download PDF

AMIGA NEWS TECH numero 22 (05-1991)

Document sans nom AMIGA
LE MAGAZINE DES PROGRAMMEURS SUR AMIGA - N 22 - MA11991
MM. NEWS'TECH
Edito News 2 ExecBase : Utiliser Amiga.lib 3
Stéphane Schreiber Denis Jarril François Lionel François G ne i (gnon Mips
HDV Gluten... Frédéric Mazué Loïc Far Philippe Rivaillon Jérôme Etienne Frédéric Mazué HDV Gluten...
Max
Frédéric Mazué Cats
AMOS : AMT Troisième 4
Arexx : la Voie Royale 6
ToolBox : Le compilateur GfA-Basic 8
ToolBox 2 : Compilateur Pascal "DP" : PCQ 10
Debug : Alea Jacta Est 12
ExecBase 2 : Le 68000 de A à Z 14
Concours Lecteurs : Dégradé 16
Démos : La 3D 18
Utilitaire : EasyWindow 22
SUB.way : Les Gadgets 26
SUB.way 2 : Les Resources 28
Requester : Le cours rieur délecté 30
CATS : Deboguez vos programmes 32
"Roger ne s'est pas rasé ce matin"
Dessin de Pierre Bretagnolle, réalisé en 2 couleurs seulement, ça valait la peine d'être souligné.
1991
Ediîo
OURS
Vous savez quoi ? J’ai horreur d’écrire ic nounours. Parce qu'il doit tenir sur une colonne complète, et comme il n'y a vraiment pas grande chose à dire dedans, ça m'oblige à y raconter un peu ma vie. Alors que. Franchement, il y a tout de même des choses plus intéressantes à lire dans ce journal, non ? M'enfui, la loi c'est loi. On est obligé de mettre un ours, un point c'est tout.
Tenez, par exemple, combien parmi vous sont intéressés par le fait que l'Amiga News-Tech. ANT pour les intimes, est une publication de Commodore Revue SARL hein ? Surtout que le coupon d'abonnement, vous l'avez trouvé dans Commodore Revue, non ? Mais tant pis. C'est obligatoire. De même que l'on préciser que Commodore Revue SARL ça se trouve au 5. Rue de la Fidélité. 75010 Paris. Voilà, on l'a dit.
La rédaction, ça vous intéresse sans doute pas plas ? Ben pourtant, le Directeur de la Publication (je mets des majuscules exprès, comme ça il se sent important) s'appelle Jean-Yves Primas. C'est lui qui va à Ncvv-York quand y'a des salons importants. Quand y'en a pas aussi, d'ailleurs. Bon. Son numéro de téléphone, c'est le ( 1 )
4147. 1116.
Le Rédacteur en Chef s'appelle Yves Huitric. Ce qui vous fait sans doute une belle jambe. Ce cher Yves cumule d'ailleurs les fonctions, puisqu'il est également Maquétistc en Chef. Crapiton en Chef et Chef en Chef. Bref, c'est lui le chef.
Tout Chef qui sc respecte ayant besoin d'un adjoint pour faire le boulot à sa place, on a choisi Stéphane Schrciber parce qu'il sortait de l'armée, complètement désorienté et que deux sourires ont suffit à remettre un peu de joie sans ses veux désabués. Même pas eu besoin de le saouler !
Les pigistes, maintenant. Ce sont eux qui écrivent les articles super-extra-déments que vous lisez avec avidité. Par odre alphabétique, on a Pascal ''Doktor" Amiable. Denis "Barbare” Jarril, Jérôme "méga-coder" Etienne, Loïc "Le Bcta" Far. François "Rexx" Gucugnon, François "Daisy" Lionet. Frédéric "RKM” Mazué. "Mini" Max. MIPS "Benchmark" et Stéphane "A3000” Schrciber.
Si vous aviez lu l'Edito ci-contre, je n'aurais pas besoin de répéter qu’un problème d'abonnement se résoud toujours chez Ami sa VPC au (1)43.78.9110.
Voilà pour nous. Au tour des autres : c'est CdorWay qui flashe nos pages à partir des fichiers PostScript de ProPage
10. ColorWay, qui sc trouve au
5. Me de la Fidélité. 75010 Paris. Vous pouvez pas les rater, c'est juste l'étage en dessous de chez nous. Leur téléphone est le (1)
47. 70.87.87. L'imprimeur, lui. Sc trouve à Reims et s'appelle N. I. C Son téléphone est le (16)
26. 07.57.87.
"Bougez avec la Poste", qu y disaient... "Pas de problème, la Poste est là", qu ’y disaient...
Pourtant, d'après quelques coups de téléphone reçus à la rédaction certains abonnés reçoivent leur ANT avec beaucoup de retard. Nous les envoyons pourtant dès le 15 du mois ; accordons gracieusement une semaine de délai aux P&Tpour la distiibution : vous deviiez recevoir votre ANT au plus tard le 22 du mois. Mais il est également possible que Teneur vienne de nous (que voulez-vous, personne n'est pat fait... ). Si passée cette date, Soeur Anne n 'a toujours rien vu venir, n 'hésitez surtout pas à téléphoner au (1)
43. 78.92.10pour expliquer votre cas.
Auti'es problème dû à la Poste : un lecteur nous a renvoyé sa disquette carrément pliée en deux par le facteur, pour la faire rentrer dans la boîte à lettres ! Il est bien évident que ni TANT ni Commodore Revue SARL ne sauraient être tenues pour reponsables de cette situtation. Toutefois, nous échangerons volontiers toute disquette abîmée ou défectueuse ; il vous suffit pour cela de nous renvoyer celle en cause, accompagnée d'une enveloppe auto-adressée et, bien sûr, timbrée.
Et n'oubliez pas que pour toutes vos suggestions, critiques et compliments sur TANT, je vous attends sur le 3615 COMREV, mbrique ANT, en Tribune 'Stéphane Schreiber" ou en BAL ANT.
Un rédacteur anonyme...
PS : R. I. P. Le serveur Deep, bien connu de tous les Amigaïstes, est officiellement mort de 28 mars 1991. Tous les "branchés"perdent là l'un de leurs lieux de rencontre les plus appréciés. L’équipe complète de TANT se joint à moi pour souhaiter à François, le sympathique sysop, une bonne continuation et beaucoup de chance dans l'avenir.
Stéphane Schreiber.d
Minitel : l'Agenda
Vous avez envie de discuter avec l’un des rédacteurs de TANT ? Rien de plus facile, il vous suffit de vous connecter sur Minitel, code 3615 COMREV, taper ANT au sommaire général. De là, rendez-vous sur le Débat, en fonction de l'Agenda ci-dessous.
Her?- Doktor Von GluttenStimmelîmDorf : Lundi Stéphane Schreiber : Mardi Frédéric Mazué : Mercredi Max : Jeudi
A-PA-PA-PA-PA-PA-PA-PA-P
Vends carte Passerelle PC pour A2000 avec lecteur de disquettes 5"1 4, logiciels nécessaires à l’installation et l’utilisation (MS-Dos, GWBasic...). Vends dans le même lot : Quick Basic 4.5, Multiplan 3, Dbase 111. Le tout avec documentations : 4000 F. Pour tout renseignement : (16)
43. 77.81.91 aux heures de bureau Demander Alain.
François Lionet : Vendredi (sous résefve)
Vous y trouverez le journaliste de votre choix le jour indiqué, à partie de 19 heures. Concernant François Lionet, sa situation actuelle ne lui pennet pas d’assurer une permanence régulière le jour-dit. Son agenda définitif sera publié directement sur le serveur.
.LIB (II) |
*
.lib [NODEBOG]
M
Effectue une sortie formatée sur stdout Affiche une chaîne + CR sur stdout Affiche un caractère sur stdout Lit un caractère depuis stdin Effectue une sortie formatée dans un fichier Envoie une chaîne + CR dans un fichier Envoie un caractère dans un fichier Lit un caractère depuis un fichier Effecture une sortie formatée dans un buffer
l'adresse $ %lx (%ld)",$ 0a,0
ais avant de commencer, je me dois de vous présenter mes excuses : j’ai en effet commis une bourde aussi grosse que moi en concluant, le mois dernier, par l’évocation d’une hypothétique sortie ASCII de nombres en virgule flottante... Cette manoeuvre sournoise ne pouvait qu’être destinée à capter votre attention d'une manière parfaiteusement honteuse, étant bien entendu que ce n'est pas amiga.lib qui contient de genre de routine, mais lcm.lib (en tout cas pour le Lattice : pour l'Aztec, désoîé, je ne sais pas).
Il est donc maintenant question d’utiliser amiga.lib pour une série de tâches dont il serait bien inutile de ré-écrire soi-même le code, des bonnes âmes charitables s’en étant déjà chargé pour nous. Comme disait mon grand-père : "y'en a qui aiment le boulot, autant le leur laisser".
Pour illustrer la manière dont il faut s’y prendre, je vous ai concocté un petit programme de démonstration. Il contient des appels à diverses fonctions d'amiga.lib. aussi bien du module "exec_support" que du module "clib" (reportez-vous à l’article du mois dernier pour plus de détails).
PARAMETRES
C est maintenant bien connu, le langage C passe les paramètres des fonctions qu'il appelle par l’intermédiaire de la pile, en sens inverse de leur énumération. Par exemple, la ligne
tuf fer = AllocMem( 10000, MEMF_ŒIP|MEMF_CLEAR) ;
est compilée en :
MOVE.L $ 10002,-(A7) ; MEMF_CHIPIMEMF_CLEAR
MOVE.L $ 2710,-(A7) ; 10000
JSR _AllocMem(PC) ; Saut à AllocMetn
addq.l 8,A7 ; Correction de la pile
Il faudra en tenir compte plus tard, toutes les fonctions d"amiga.lib ayant été écrites en C. Au passage et pendant que j’y pense, l'instruction PEA du 68000 est très pratique pour celui qui manipule souvent la pile : elle à le même effet (et la même syntaxe) qu’un LEA suivi d'un empilement du registre, mais évite, justement, l’utilisation d'un registre.
CLIB
La partie baptisée "clib" d’amiga.lib contient quelques fonctions directement empruntées a la librarie standard du C. stdio, à savoir :
printf puts putchar getchar Fprintf (puis Iputc Igetc sprintf ’
Toutes ces fonctions s’utilisent quasiment de la même manière que leurs homonymes de la bibliothèque C standard. Quelques petites différences subsistent toutefois :
- elles utilisent RawDoFmtO d'exec.library (spécifique Amiga) ;
- les nombre réels ne sont pas supportés (la honte sur moi) :
Au fait, vous avez remarqué que certaines font appel à stdin ou à stdout ? Ce sont, en C. les canaux standard d entrées-sorties. Avec stderr (utilisé pour les messages d'erreur). Ces pointeurs doivent être valides lors de l'appel aux fonctions, d où l'ouverture de la dos.library en début de programme, et l'appel aux fonctions lnput() pour stdin et Output() pour stdout. Quant à stderr. Il est initialisé avec Qpen("*"), ce qui l'empêche d'être redirigé avec les caractères > et du CLI...
ASSEMBLAGE
Le programme Clib.s (original, non ?) Doit évidemment être assemblé en code linkable. Case-dependènt. Avec ou sans symboles, c'est pas grave. Les
Après avoir vu à quoi servait la fameuse amiga.lib, si chère à tous les programmeurs en C, nous allons aujourd’hui nous intéresser à la manière de l’utiliser dans des programmes en assembleur.
Nous verrons le mois prochain comment intégrer des routines assembleur dans un programme en C et inversement (si, si, ça peut être utile !). D’ici là je vous souhaite un bon mois en notre compagnie.
Denis Jarrii
; *** Options : linkable, case-sensitivity on OPT L+,C- inedir "include:" include "exec ports.i" include "exec exec_lib.i" include "libraries dos.i" include "libraries dos_lib. I"
; *** Symboles qu'on exporte
XDEF _SysBase ; défini dans exec exec_lib.i
XDEF _DOSBase, _stdin, _stdout, _stderr
; *** Symboles qu'on importe
XREF _printf,_puts,_fprintf,_fgetc XREF _CreatePort,_DeletePort
; *** Débit du programme
Start lea dosname(pc),al ; ouvre dos.library moveq 0,d0 CALLEXEC OpenLibrary inove.l dO,_DOSBase beq DosErr CALLDOS Input
move.l dO,_stdin ; sauve stdin CALLDOS Output
inove.l d0,_stdout ; sauve stdout move.l console,dl ; ouvre stderr ('*') move.1 M0DE_OLDFILE,d2 CALLDOS Cpen move.1 dû,_stderr ; *** Affiche la chaine 'messl'
pea messl(pc) ; (char *)messl jsr _puts .
Addq.l 4, sp ; corrige la pile (1 mot long)
; *** Affiche l'adresse de dos.library en hexa et en décimal move.l _DOSBase(pc),-(sp) ; enpile _DOSBase move.l _DOSBase(pc),-(sp) ; enpile _DOSBase pea mess2(pc) ; (char *)mess2 jsr _printf
lea 12(sp),sp ; corrige la pile (3 mots longs)
,- *** Crée un MsgPort avec CreatePort( ) moveq 0,d0
move.l dû, - (sp) ; Pri = 0
move.l dO, - (sp) ,- PortName = NüLL
jsr _CreatePort
addq.l 8,sp ; corrige la pile (1 mot long)
move.l d0,myport beq. S PortErr ; *** Affiche son type et son adresse move.l d0,a0
move.l a0,-(sp) ; enpile l'adresse du port
move.b MP_FLAGS(aO),-(sp) ; Empile un WORD i pea mess3 (pc) ; (char *)mess3 jsr _printf
lea 10(sp),sp ; corrige la pile (2 longs + 1 mot)
; *** Détruit le port avec DeletePort()
move.l myport(pc),-(sp) ; enpile 'myport' jsr _DeletePort
addq.l 4,sp ; corrige la pile (1 mot long)
; *** Affiche un message sur _stderr et attend une touche pea mess4a(pc) ; enpile 'mess4a' pea mess4b(pc) ; enpile 'mess4b' move.l _stderr(pc), - (sp) ,- enpile 'stderr' jsr _fprintf
lea 12(sp),sp ; corrige la pile (3 mots longs) move.l _stderr(pc),-(sp) ; enpile 'stderr' jsr _fgetc
addq.l 4,sp ; corrige la pile (1 mot long)
PortErr move.l _stderr(pc) ,dl ; ferme stderr CALLDOS Close
move.l _DOSBase(pc),al ; ferme la dos.library CALLEXEC CloseLibrary DosErr moveq 0,d0 ; retour au CLI
rts
messl
dc. b
"Hello world !",0
even
mess2
dc. b
"dos.library est à l'adi
even
mess3
dc. b
"Création d'un port de I
dc. b
"CreatePort() à l'adresi
even
mess4a
dc. b
10,"Appuyez sur Rnter>
even
mess4b
dc. b
"%s",0
even
_DOSBase de.
.1 0
_stdin
dc. l
0
stdout de. 1
0
_stderr de. 1
0
myport
de .1
0
dosname de .b
"dos.library",0
even
console de .b
"*",0
even
Blink FRCM Clib.O TO Clib LIBRARY LIB:
possesseurs de Devpac II sauront comment faire, et les possesseurs de K-Seka peuvent toujours changer d'assembleur. Le linkage est obtenu (avec Blink du SAS C) par la ligne de commande :
MOS TECHNIQUE II
tous les plans mémoire de l’image. Le masque obtenu rend la couleur 0 transparente. On peut, connaissant la structure de la banque, calculer différemment le masque, et rendre d’autres couleurs transparentes. Encore plus intéressant, l’instruction SETBOB permet de choisir la relation logique entre DECOR, IMAGE et MASQUE lors de l’affichage d'un bob. En passant de longues heures à choisir les couleurs et les paramètres de calcul (MINTERMS pour les initiés), on peut arriver à des effets époustouflants... Bon, ce sera pour une prochaine fois, je suis déjà en retard pour l’article que vous lisez et j’ai un compilateur à terminer !
¦
LANGAGE :
Nous allons maintenant commencer à décrire le format des banques de mémoire AMOS: en premier lieu, les banques de sprites et d’icônes, dans la mémoire et sous la forme de fichier.
Le programme assembleur qui suit est une petite routine (262 octets à peine) faisant le calcul d'un masque complexe. Elle est conçue pour être chargée dans une banque mémoire, et constitue un bon exemple d'appel de routine en banque. Pour l’utiliser, assemblez le programme, sauvez le code produit sous le nom de "Masque" et tapez, en mode direct dans AMOS :
Lla banque de sprites, qui porte le numéro 1 ("vous êtes le numéro 6. Nous voulons des informations"), contient dans une même zone de mémoire les définitions des sprites et des bobs. Dans ce qui va suivre, je parlerais donc indifféremment de sprites et de bobs, ce qui me simplifiera d’autant la vie. La structure de la banque en mémoire est un peu particulière : elle n’est pas en un seul bloc, mais plutôt répartie dans tous les espaces libres disponibles.
La fonction =Start(l) ramène l’adresse de l’entête de la banque de sprites. Celui-ci contient les pointeurs sur les dessins proprement dits, ainsi que la palette de la banque.
Voici la structure de la banque sous la forme d’un listing assembleur :
* Nom de la banque
dc. b "Sprites "
* Pointeurs sur les images Start de.w Ncmbre_De_Sprites
PLOftD "Masque",15
La routine se trouve maintenant dans la banque numéro 15. Elle sera sauvée avec votre programme AMOS. Il n’est plus besoin de la recharger.
NB: une routine chargée ainsi EXDIT être totalement relogeable et ne comporter qu’un seul HUNK. Vous devez donc faire du code relatif-PC.
Une démonstration AMOS de cette routine suit le programme langage machine. Elle propose une procédure :
MASQOE[numéro,Ml,M2]
sachant que :
- numéro est le numéro du sprite dans la banque :
- Ml et M2 sont les parties haute et basse (respectivement) des couleurs transparentes. La couleur correspondante à chaque bit mis à 1 sera transparente.
Nombre_De_Spntes
REPT
dc. l Adresse_du_dessin (1)
dc. l Adresse_du_masque (2)
* Palette de la banque (32 mots) ds.w 32
Exemples :
- M 1=0 et M2= 16 : la couleur 4 est transparente ;
- M1=S00000001 et M2=S80000000 : les couleurs 31 et 32 sont transparentes.
(1) L’adresse du dessin peut être nulle. Dans ce cas il n’y a évidemment pas d’adresse de masque. Une adresse nulle est obtenue avec l’instruction DELETE SPRITE. En éliminant un sprite au beau milieu de la banque.
(2) L’adresse du masque peut prendre valeurs différentes :
* 0 : il faut fabriquer un masque. Le masque sera calculé lors du
premier affichage du bob ;
* -1 : l'instruction NO MASK a été appliquée à ce bob ;
* >0 : pointeur sur le masque.
Chaque bob ou sprite est un petit morceau d’écran, contenant les données du dessin, plan par plan (les anglais appellent ça les "bitplanes"). Les plans mémoire se suivent, dans l’ordre croissant.
Rien ne vous empêche d’utiliser les informations des AMT précédents pour fabriquer une nouvelle extension à l'AMOS, et rajouter de nouvelles instructions...
NB1 : la détection de collision utilise le masque du bob pour déterminer les croisements entre bobs. Elle n'est valide qu’avec le masque par défaut, et pas avec ceux produits par cette routine.
NB2 : le masque n’a - évidemment - aucun effet sur l’affichage des sprites.
LA BANQUE D’ICONES
Le format d’une banque d’icônes (banque numéro 2) en mémoire est exactement le même que celui d’une banque de sprite. La seule différence tenant dans l’entête, qui est :
Adresse_du_sprite:
de.w Taille_en_X (en de.w Taille_en_Y de. W Ncgibre_de_plans
de.w Point_chaud_en_X OR Flags_Retouraements de.w Point_chaud_en_Y
* Données image
REPT Hanbre_de_plans
dcb.w Taille_en_X * Taille_en_Y
de MOTS = TX 16)
dc. b "Icônes "
Start: de.w Nombre d'icônes
Vous pouvez donc appliquer le calcul des masques aux icônes !
Les Flags_Retoumements sont produits à partir de la version 1.21 d’AMOS. Le bit 15 correspond à un retournement en X, le bit 14, à un retournement en
Y. Le point chaud en X n’est calculé que sur 14 bits signés (cf. Anciens numéros de l’ANT) !
Le masque, lorsqu’il est défini, contient un seul plan mémoire. Les bits du masque à 0 sont transparents (on voit le décor "au travers”), les bits à 1 sont opaques (on voit le sprite).
FORMAT D’UNE BANQUE SUR DISQUETTE
Voici le format du fichier obtenu par la sauvegarde d’une banque de sprites (SAVE "Banque.Abk",l) :
* Code de reconnaissance
dc. b "AmSp” de .w Nccibre_de_sprites
Adresse_du_Masque:
T Ifc«nbre_de_sprites de.w Taille_en_X de.w Taille_en_Y de .w Nanbre_de_plans de.w Point_chaud_x
dc. w Point chaud_Y
e_de_plans dcb.w Taille enX * Taille_
de.1 Taille_du_masque_en_octets dcb.w Taille_en_X * Taille_en_Y
CALCULER SON PROPRE MASQUE
Connaissant la structure de la banque de sprites, il est tout à fait possible de calculer soi-même le masque d’un bob, et d’obtenir ainsi des effets très intéressants. AMOS calcule le masque en effectuant un OU logique entre
par François LIONET "1 | ?
* Palette de 32 couleurs dcb.w 32
AMOS ne sauve donc pas les masques, pour gagner en rapidité. Un sprite vide est marque par "dc.w 0,0,0,0,0”, et pas de plan d’image.
Les sprites sont toujours retournés dans leur direction "originale" avant d'être sauvés. Les flags du point chaud en X sont donc toujours égaux à zéro (pour rester compatible avec les premières versions d’AMOS).
Une banque d'icône ne diffère que par son code de reconnaissance, qui est ici :
Voili-voila pour ce mois ! La prochaine fois, quelque chose de beaucoup plus compliqué : la banque de musique. Nous verrons comment mettre plusieurs musiques dans la même banque.
B
Préparé la boucle move.l subq.l move.w subq.w lea
Calcul de masque corplexe
* A0->
Banque de sprites
* D0->
Numéro du sprite
* Dl D2->
Cculeur transparentes *
_LVOallocmem equ -198
_LVOfreemem
equ -210
Chip
equ $ 02
Public
equ $ 01
Œip. 1
”Spri",-8(a0)
Une banque de sprites?
Bne
Erreur
cnp.w
(a0)+,d0 Si > au
nombre de sprites
thi
Erreur
lsl.w
3,d0
lea
- 8(a0,d0.w),a5
Adresse des addresses !
Move.l
(a5)+,d0
beq
Erreur
move.l
d0,a4
A4= SpriteBase
* Fabrique la table
lea
Table(pc),a0
cirp. 1
(a0),dl
bne. S
DoTable
erp. 1
4(a0),d2
beq.s
PaTable
DoTable
move.l dl,(a0)+
move.l
d2,(a0)+
moveq
64-1,dO
TableO
clr.b (aO)
lsr.l
l,dl
roxr.l
l,d2
bcc.s
Tablel
subq.b
1, (aO)
Tablel
addq.l l,a0
dbra
dO,TableO
PaTable
* Calcul de la taille du masque
move.w
(a4),d7
TX
lsl.w
l,d7
En mots
mu lu
2(a4),d7 fois TY
* Reserve la mémoire (s'il faut!)
Move.l
(a5),d0
beq.s
Reserve
bpl.s
DejaLa
Reserve
move.l d7,d0
addq.l
4,d0
move.l
d0,d2
move.l
$ 4,a6
move.l
Chip | Public, dl
CHIP rnemory seulement
jsr
_LVOAllocMem (a6)
move.l
dO,(a5)
beq
Erreur
move.l
d0,a0
move.l
d2,(a0)+ Lobe la
taille
DejaLa
move.l d0,a2
addq.l
4,a2
d7,d6 D6-> Taille d'un plan
l,d7 D7-> Carpteur d'octets
4(a4),d5 D5-> Nombre de plans l,d5 -1 pour DBRA
10(a4),al Al-> Base du dessin
A2-> Adresse du masque
lea
Table+8(pc),a3
A3-> Table de masque
* Boucle de calcul
.locpO moveq
7,d3
D3-> Carpteur bit
.locpl moveq
0,d0
D0-> Calcul couleur
moveq
0,dl
Dl-> Position bit
move.w
d5,d2
D2-> Carpteur plans
move.l
al,a0
A0-> Pointeur octet
.loop2 btst
d3,(aO)
beq.s
.locp3
bset
dl,d0
.locp3 add.l
d6,a0
Passe au plan suivant
addq.w
l,dl
dbra
d2,,loop2
bset
d3,(a2)
tst.b
0(a3,d0.w)
Couleur transparente '
beq.s
.loop4
bclr
d3, (a2)
.locp4 dbra
d3,. Locpl Encore
un bit?
Addq.l
l,al
addq.l
l,a2
dbra
d7,. LoopO Encore
un octet?
* Ca y est, pas d'erreur
moveq
rts
0,d0
* une erreur!
Erreur moveq rts
-l,d0
Table ds .b
64+8
LISTING 2
Démonstration du calcul de masque
Charger la banque progranme en mode direct: PLOAD -Masque",15
Charger également une banque de sprites!
Flash Off : Curs Off Get Sprite Palette Cls 0
For N=0 To 15 Paper 0 : Pen N
Centre At(,N)+"Cette ligne est en couleur"+Str$ (N) Next
Double Buffer Repeat
Pen 1 : Centre At(,20)+"Masque demandé:”+Str$ (C) MASQUE[1,0,C]
Repeat
Bob 1,X Screen(X Mouse),Y Screen(Y Moïse),1
Wait Vbl
Ontil Mouse Key
Inc C
Ontil Mouse Key=2 Default
Procédure MASQUE[N,Ml,M2] Areg(0)=Start(1)
Dreg(0)=N
Dreg(l)=M1 : Dreg(2)=M2 Call 15 If Dreg(0)
End Proc
Error 23 : End If
00 imfo
1 AMOS FRANÇAIS EST ENFIN SORTI !
SA DISTRIBUTION EN FRANCE EST ASSUREE PAR UBISOFT. PRIX : 499F
LANGAGE :
Rexx est un langage qui existe depuis 1985, et son succès sur d’autres machines a tout naturellement provoqué le désir de le porter sur Amiga. Son introduction dans notre excellente machine date de 1987 et a été réalisée par W. S. Hawes qui s’est efforcé, le fait est remarquable, de coller le plus parfaitement possible à la définition de Rexx, de sorte que ceux qui connaissent Rexx ne seront pas dépaysés.
!?
&REXX LA VOIE RC
bien le dire, à nul autre pareilles.
En tant que langage de programmation. Arexx est utile à un large spectre d’utilisateurs. Il est à la fois très facile à apprendre, car s'apparentant au Basic, et très puissant. Toutefois, au lieu de viser à l'universalité, il est principalement orienté vers le traitement des caractères et très bien adapté comme langage de commandes. Les programmes de commandes sont fréquemment appelés "scripts" (ou. Plus techniquement, "macros") ; ils sont écrits dans un fichier de type texte et sont largement utilisés pour élargir l'ensemble des commandes prédéterminées d'un logiciel ou pour en personnaliser une application.
Par contre, ses capacités mathématiques sont faibles et les graphiques inexistants. Que l'on se rassure toutefois, l'appel aux bibliothèques spécialisées pallie à cette apparente faiblesse.
Nous verrons donc par la suite comment Arexx permet :
Pendant quelques temps, Arexx n’a été l'apanage que de quelques spécialistes et d’amateurs avertis, juste le temps d’atteindre la version 1.15. Les hommages lui furent alors rendus, qui le placent désormais au rang des fonctions de base de l’Amiga 3000. Mais malgré son succès, dû à son intérêt, sa popularité n’a pas atteint, à notre sens, le niveau qu’elle devrait logiquement avoir. En inconditionnels d’ARexx, après l'avoir été de Rexx, nous développerons dans ces colonnes successivement : la présentation, l'intérêt, les modalités d’emploi et enfin l’utilisation de Arexx dans une présentation qui associera les règles théoriques et les exemples pratiques de façon à satisfaire tant lé débutant ou l'exploitant moyen, que l'exploitant le plus expérimenté de l'Amiga (du 500 au
3000) . Une ouverture enfin sera donnée au programmeur développeur qui ne saurait aujourd'hui réaliser un bon produit sans une inclusion de Arexx dans le fruit de ses travaux, utilitaire ou jeu !
AVERTISSEMENT
Différents articles traitant d'ARexx, de niveaux différents, ont déjà paru dans différentes publications, si bien qu'il doit exister en conséquence différents niveaux parmi les lecteurs. Que les plus avancés patientent un peu pendant que les moins avancés et les nouveaux prendront place dans les rangs. Pour la cohérence d’une suite d'articles, il importe aussi de commencer par le début et de suivre un enchaînement logique.
INTRODUCTION
La question première qui fuse lorsqu’on évoque Arexx est bien évidemment : "qu'est-cc que c’est ?". La réponse est nette et définitive : c'est un langage de programmation de haut niveau !
Pour les uns, la déception est grande, qui leur fait craindre un travail supplémentaire. Du Basic au Pascal, en passant par les Forth, Lisp, Prolog. Fortran (de 1 à 77 !), Cobol divers, APL. PLI. LTR. ADA. Qu'avions nous besoin d'un langage supplémentaire, et pas même TURBO ?
De haut niveau avez-vous dit ? Voilà qui va nous mettre à dos la cohorte des attardés de l'assembleur 8 16 bits et faire ricaner les subtils experts du C ! Il n'entre bien évidemment pas dans nos visées de déclencher une polémique quelconque, aussi stérile qu’inutile tant il est vrai que ces modes de programmation ont leur intérêt et fait leurs preuves !
Mais il faut bien appeler les choses par leur nom. C'est toutefois faire injure à Arexx, qui, s’il entre dans cette catégorie à cause de son formalisme, présente des caractéristiques tout-à-fait séduisantes et. Il faut
- la commande directe à partir du clavier, à la façon d’un CLI ou d'un Shell :
- la réalisation de petits programmes spécifiques, écrits en quelques minutes et effectuant des opérations quasi-magiques ;
- la réalisation de scripts correspondant à l'exploitation des progiciels du commerce dont l'emploi avec Arexx est prévu et dont l'exécution peut être déclenchée de l’intérieur ou de l'extérieur de ce progiciel.
Si bien que tout en étant un langage de haut niveau. Arexx est plus réputé comme "interpréteur de commandes", incomparablement plus riche que ne peuvent être les CLI ou Shell qui n'ont pas ses spécifités d'ouverture.
DISPOSITIONS SPECIFIQUES IMPORTANTES DE AREXX
Quelques particularités importantes spécifiques de Arexx doivent maintenant être précisées, pour montrer ses intérêts premiers.
- Données sans type : les données utilisées par les instructions ou les fonctions, sont traitées comme des chaînes de caractères sans type (alpha, numérique, etc). Il n'est pas besoin non plus de déclarer les variables avant usage et toutes les opérations vérifient dynamiquement la validité des opérandes, de façon à réaliser uniquement des opérations cohérentes. Cela s'applique également aux tableaux (ou STEM) qui n'ont besoin ni d'être dimensionnés. Ni même d'être de type unique, c'est-à-dire qu’ils peuvent être mixtes. Ils ont d'autres propriétés intéressantes que nous verrons plus loin.
- Interface de commande : les programmes Arexx peuvent fournir des commandes aux programmes externes qui proposent l'interfaçagc approprié. N’importe quel logiciel ou progiciel de ce type est entièrement programmable ou paramétrable suivant les cas. Et peut être étendu sans limite par l'utilisateur final, au moyen d'un ou de plusieurs scripts. Cela veut dire aussi que le développeur peut limiter l'effort d'étude de son interface avec l’utilisateur (écran, clavier) à l’indispensable ou le strict nécessaire, en laissant à l'utilisateur le soin, et pourquoi pas le plaisir, de définir scs propres accès au logiciel, d'en changer pour en améliorer la fonction et, pour celui qui veut rester en dehors de "tout cela", proposer un interfaçage standard.
- Trace et "Debugging" : Arexx contient des facilités de déverminage des programmes au niveau source, qui permettent au programmeur de suivre les actions de son programme pas à pas pendant son fonctionnement. Un système d'interruption interne permet une manipulation spéciale des erreurs qui auraient par ailleurs provoqué l'arrêt du programme. La fonction TRACE, munie de nombreuses options, ce qui est inhabituel dans de tels langages, permet de suivre, éventuellement sélectivement, tout ce qui se passe pendant l'exécution du programme y compris l’interactivité avec l’utilisateur et la mémorisation de la "TRACE".
VALE
François GUEUGN
- Exécution interprétée : les programmes Arexx sont mis en oeuvre par un interpréteur. Cela veut dire qu'il n’est pas nécessaire de les compiler et de les "linker", et qu’ils sont exécutables dès qu’ils sont tapés ! Bien que cela réduise la vitesse d’exécution (et, ici, pas de façon très sensible) cela simplifie grandement la réalisation des programmes.
- Librairies de fonctions : des librairies de fonctions externes diverses peuvent être utilisées pour élargir considérablement les possibilités du langage, ou faire des passerelles vers d’autres programmes.
- Gestion automatique des ressources : l’allocation et la dé-allocation de la mémoire interne, en relation avec la création et la destruction des chaînes de caractères et autres stuctures d'information, sont entièrement automatiques. Elles libèrent le programmeur de ce souci tout en assurant une occupation minimale de la mémoire.
- Capacité de programmation dynamique : certaines instructions d’ARexx permettent de résoudre certains problèmes de programmation d'une façon intéressante et nouvelle.
Avec la possibilité d’interpréter, le programmeur peut demander au programme d’exécuter des variables chaîne de caractères comme si c’étaient des instructions. Un programme peut donc être conçu non seulement pour créer des lignes de programme, mais encore pour les exécuter. Des fragments de programme peuvent aussi être passés comme des arguments à des fonctions qui peuvent aussi les interpréter.
Bien que cela soit plutôt réservé à ceux qui jouent dans la cour des grands, cette activité, dans Arexx, est accessible sans difficulté à tout programmeur.
APPLICATIONS D’AREXX
Nous nous sommes volontairement limités dans une introduction qui aurait dû autrement changer de nom. Il reste encore de nombreuses et belles pépites dont l’accès est aussi simple que le reste.
Tout ce que nous avons dit est sans doute très beau, mais ne parle guère au néophyte qui en est toujours à la première question : à quoi tout cela sert-il ? Aussi allons-nous dès à présent essayer à la fois de satisfaire sa curiosité et lui donner l'envie, ainsi qu'aux autres, d'aller plus loin.
Premier exemple: il est de notoriété publique que l’impression du répertoire d’une disquette est résolument triste si l'on utilise la commande du CLI. "DIR > PRT:". Même avec l'option A ou N, on n'obtient ni toutes les informations désirées, ni une présentation très "classe" ! Nous pourrions souhaiter mieux, par exemple :
- imprimer le nom de la disquette ;
- donner le nombre de fichiers dans la disquette :
- imprimer les répertoires avec une indentation à droite au fur et à mesure de leur niveau relatif :
- changer la couleur et ou la police de caractères :
- écrire le contenu classé par ordre alphabétique, ou par ordre de taille ou tout autre classement au choix ;
- donner entre parenthèses la taille de chaque fichier ;
- effectuer des calculs indiquant la place restante sur la disquette ;
- indiquer pour chaque fichier son degré de protection ;
- etc, etc.
Ce genre de programme demandera plus de temps à l’utilisateur pour définir ce qu’il souhaite voir après impression, que pour taper les commandes dans un fichier script. Nous en ferons un exemple appliqué dès les premiers essais de programmation à venir.
Second exemple : les disquettes du Domaine Public, en particulier celles, remarquables, de Fred Fish, ont la particularité d'être organisées selon un plan constant. La disquette a un nom qui contient son numéro d'ordre dans la collection, il y a un fichier, qui a toujours le même nom, donnant des indications générales sur l’intérêt et l’emploi des programmes contenus dans la disquette. Nous pourrions donc vouloir imprimer le nom de la disquette, tenir à jour une liste par valeur numérique ordonnée des disquettes en notre possession (même si nous ne les possédons pas toutes et si nous ne les avons pas obtenues dans l’ordre), imprimer les répertoires, les principaux étant précédés par le texte explicatif, et sauvegarder le tout dans un fichier répertoire spécialisé.
Là encore, le plus grand travail consistera à définir ce que l’on veut. Le programme, comme tous les autres (à l’exception de ceux d'intelligence Artificielle), étant incapable de discerner nos goûts en la matière. Néanmoins son écriture ne devrait pas dépasser quelques dizaines de minutes.
Troisième exemple (et le plus délicat) : imaginons que nous ayons une banque de données réalisée sous un logiciel X (disons au hasard DBMan, ou. Dans sa version française InfoFile). Mais pour des raisons dont nous n’avons pas à nous préoccuper, nous voudrions bien passer sous, encore au hasard, SuperBase. Il existe bien des méthodes mais la question des délimiteurs fait que cela n'est pas aisé, sinon impossible.
Voici donc la procédure utilisable sous Arexx : tout d'abord, éditer le fichier de données dont on se sert. C’est un fichier relativement illisible mais dans lequel il y a obligatoirement les noms des champs associés à chaque élément : par exemple nom, adresse, numéro de téléphone, etc. Chaque fiche est construite de la même façon, et il y a aussi obligatoirement une périodicité de nombre de caractères ou de type de caractères : les délimiteurs. Il faut repérer tout cela précisément.
On crée ensuite dans la banque de données nouvelle que l’on souhaite utiliser, un fichier contenant 2 ou 3 fiches strictement identiques à celles de la banque de données initiale. On se livre ensuite au même travail de repérage. A la fin, on dispose du modèle de chacune des méthodes de stockage des deux banques. C’est ici qu’ARexx entre en jeu. Comme il ne s’intéresse qu’aux caractères, on va écrire un programme qui va lire dans le premier fichier (celui que l'on veut transposer) une série de caractères, égale ou supérieure à celle qui est nécessaire pour obtenir l'équivalent d’une fiche. On en tirera les valeurs utiles, à savoir les noms, adresses, numéros de téléphone, etc. Puis on construira une définition, caractère par caractère, d’un fichier formellement identique à celui de la banque nouvelle que l’on veut utiliser, en plaçant là où il le faut les valeurs (data) extraites de la précédente. On répétera l’opération autant de fois qu’il sera nécessaire jusqu’à la fin du fichier source, en utilisant une instruction de boucle. Il ne restera plus qu’à enregistrer le fichier ainsi créé avec le nom voulu pour que la deuxième banque de données puisse s’en servir comme si elle l'avait construit elle-même.
Nous verrons dans le prochain article comment utiliser certains programmes du commerce : peinture, digitalisation, traitement de texte etc. Nous verrons aussi comment installer Arexx, ce qu'il est nécessaire de posséder et de faire pour le mettre en oeuvre et l'utiliser.
H
LE COMPILATEUR G
A Vheure où le GfA-Basic arrive en fanfare sur le marché PC, la version Atniga est relativement délaissée. Il aura fallu attendre très longtemps avant que les utilisateurs français ne puissent compiler leurs programmes, sans recourir à une version allemande ou anglaise de cette artésienne des compilateurs.
PERFORMANCES
Du côté des performances, je me suis livré à quelques benchmarks sanglants, histoire de justifier ma réputation. Voici tout d'abord une série de petits tests aussi anodins qu'efficaces pour comprendre ce qu'apporte vraiment le compilateur dans tous les compartiments du jeu... Le listing ne détaille pas l'intégralité du programme, ce qui a peu d'intérêt, mais présente chacune des procédures de test. Les temps relevés sont exprimés en secondes, poui l’interpréteur et le compilateur. Les tests ont été effectués dans un premier temps sur un Amiga 2000 standard, et ensuite sur la configuration la plus rapide que l’on puisse constituer aujourd’hui à base d'Amîsa. à savoir un 2000 équipé d’une GVP 68030 à 50 Mhz.
Le gain apporté par le compilateur est également affiché. Comme vou: pouvez le voir, tous les domaines ne sont pas affectés de la même façon.
BENCHMARKS RAPIDES GFA-BASIC
tableau
LOCAL i%,j%,K%
FOR i%=l TO 10 FOR j%=l TO 10
FOR lt%=l TO 10000 a(i%, j%) =K% NEXT NEXT j%
NEXT i%
caractères LOCAL i% LOCAL a$ ,bS
Comme l’a déjà déclaré Franck Ostrowski (cf. ANT numéro 20), il s’est à peu près vendu un GfA-Basic original pour six piratés, ce qui n'a certainement pas joué en la faveur du développement de la version Amiga. Cela dit, nous allons faire un compte-rendu de ce compilateur qui offre une accélération sensible de la vitesse des programmes, et permet surtout la diffusion de logiciels autonomes, ne nécessitant pas le moindre run-time ni de librairie additionnelle.
L'un des intérêts principaux de l'environnement du compilateur GfA vient de ce que les sources du Shell (qui permet d’utiliser le compilateur et le linker automatiquement sans passer par le CLI), sont fournis. Ces sources sont évidemment écrits en GfA. Et il est donc possible à tout programmeur de personnaliser son environnement. Par exemple, cela permet de choisir par défaut les options de compilation que l'on utilise le plus souvent. Les plus exigeants pourront même complètement ré-écrire toute cette interface.
La disquette du compilateur comprend plusieurs fichiers : GFA_BCOM. Qui est le compilateur proprement dit. GL, le linker (ou éditeur de liens pour les anglophobes), GFAlib. GFAlibrary et GFAlibrary.index, qui sont les fichiers de librairies nécessaires à la constitution du programme final, ainsi que MENUX, qui n’est autre que le programme d’environnement dont nous venons de parler.
Passons maintenant aux options de compilation, souvent très intéressantes pour l’optimisation du code.
TOUT EN OPTIONS
a$ ="GFATEST"
FOR i%=l TO 100000
b$ =LEFT$ (aS,2)+MIDS(a$ , 3,3)+RIGHT$ (a$ ,2) NEXT i%
calcul_arithmetique LOCAL i%
LOCAL j
FOR i%=l TO 100000
j=(i%*3.14159-i%) i%+i% NEXT i%
La première, %3, contrôle le type de code produit pour la division. Si %3 est activée, le compilateur génère toujours le code correspondant à une division entière. Cela est très intéressant lorsque le programme ne comporte pas de calculs en virgule flottante, car le code produit est beaucoup plus rapide et concis. Avec %3 activée, une routine simple de division sur deux longs mots est appelée. Lorsque deux variables sur deux octets sont divisées, c'est l’instruction 68000 DIV qui prend le relais.
Une autre directive. *&. Agit sur la multiplication de deux variables entières dont l’une au moins est une variable sur 4 octets. Dans le cas standard, c’est une routine de multiplication de deux variables sur 4 octets qui est appelée. Cependant, si *& est activée, l’instruction MULS du 68000 sera utilisée à la place. A utiliser avec précaution donc, car MULS multipliant deux valeurs sur deux octets, cela peut tronquer une valeur significative sur quatre octets participant au calcul.
L'option $ m réserve de la place mémoire pour le programme. D'autre part, il existe aussi des options S& et S qui optimisent les blocs SELECT..CASE en fonction de la vitesse ou de la taille du code à générer.
Pour en finir avec l'optimisation, quelques astuces : il est préférable de décomposer en plusieurs lignes des calculs complexes sur des nombres entiers, ce qu'il est inutile de faire sous l’interpréteur. D'autre part, tous les types de boucles tournent aussi rapidement une fois compilés, ce qui n'est pas le cas sous l’interpréteur où FOR..NEXT est nettement plus rapide que WHILE..WEND ou REPEAT..UNT1L. Enfin, les routines utilisant des boucles à variables globales sont souvent plus rapides que celles employant des variables locales, ce qui est souvent le contraire de ce qui se passe en C.
Test 4
PROCEDURE calcul_scientifique LOCAL i%
LOCAL j
FOR i%=l TO 10000
j=IOG(EXPCiaN(A3N(S3t(ABS COS(SIN(3.14519*i%)) )A3.14159) ) ) ) )
NEXT i%
RETORN Test 5
PROCEDURE a£fichage_textel LOCAL i%
CLS
FOR i%=l TO 10000
PRINT AT(10,10) ; "TEST D'AFFICHAGE EE TEXIE SANS 9CRQÜIN3 ";i% NEXT i%
RETORN Test 6
PROCEDURE affichage_texte2 LOCAL i%
CLS
FOR i%=l TO 1000
PRINT "TEST D'AFFICHAGE DE TEXTE AVEC SCROLLING ";i%
NEXT i%
RETORN Test 7
PROCEOTRE a£fichage_graphiqiiel LOCAL i%
FOR i%=l TO 10000 PLOT 320,240 LINE 0,0,639,479
FA ENFIN
SONDAGE :
Test 8
PROCEDURE affichage_graphique2 LOCAL i%
FOR i%=l TO 1000
PBOX 160,50,480,250 NEXT i%
LES RESULTATS
GVP
486
12. 0
5. 3
7. 4
1. 8
12. 8
1. 2
46. 2
1. 0
39. 1
3. 9
88. 6
33. 6
40. 8
38. 6
Légende :
IOT = Interpréteur CMP = Ccnpilateur
I ) Machine de test : Amiga 2000. 68000-7 Mhz. 3 Mo
Test 1 Test 2 Test 3 Test 4 Test 5 Test 6 Test 7 Test 8
(MAT) (CAR) (ARI) (SCI) (AFF1) (AFF2) (GR1) (GR2)
INT 260.7 96.5 65.0 136.2 89.3 39.2 95.7 42.9
CMP 68.8 65.6 44.6 136.2 84.3 39.2 93.4 42.9
Gain 3.79 1.47 1.46 1.00 1.06 1.00 1.02 1.0
2) Machine de test : Amiga 2000.68030-50 Mhz. 9 Mo
INT 28.6 12.0 7.4 12.8 46.2 39.1 88.6 40.8
CMP 5.5 7.6 4.4 13.1 44.9 39.2 87.4 41.3
Gain 5.20 1.58 1.68 0.98 1.03 1.00 1.01 0.99
On peut faire quelques constatations à la lumière de ces chiffres.
Premièrement, il est assez logique que la vitesse d'affichage ne soit pas ou très peu modifiée, sachant qu'elle est prise en compte pour une bonne partie par les circuits graphiques. En revanche, il est plus curieux de constater que les calculs en virgule flottante ne sont pas accélérés par la compilation. Le principal reproche que l'on peut faire à ce compilateur est d'ailleurs l'absence de support des coprocesseurs arithmétiques 68881 et 68882, ce qui limite ses prétentions dans le domaine du calcul scientifique. C'est d'autant plus dommage que le GFA offre dans ce domaine des caractéristiques uniques, comme les opérations de calcul matriciel, une petite merveille pour la CAO. L'analyse des données et autres domaines gros consommateurs de matrices.
Sur l'ensemble des programmes courants, on peut raisonnablement s'attendre à un gain variant entre 50 et 100 % après compilation. Notons toutefois que des programmes n'utilisant que l'arithmétique entière peuvent bénéficier des options d'optimisation vues plus haut, et tourner 4 à 5 fois plus vite que leur équivalent interprété.
BATAILLE D’INTERPRETES
Puisque le GFA est sorti sur PC (le compilateur n'est pas encore disponible), je n'ai pas résisté à l'idée de faire une comparaison entre l'interpréteur GFA-Basic en version 386 387 et l'interpréteur GFA sur Amiga. Voici les temps en secondes obtenus sur les mêmes tests par un 486-33 Mhz. Comparés à ceux de la GVP 50 Mhz :
Test 1 Test 2 Test 3 Test 4 Test 5 Test 6 Test 7 Test 8 (MAT) (CAR) (ARI) (SCI) (AFF1) (AFF2) (GR1) (GR2)
Sachant que les deux versions du GFA sont écrites à 100 % en assembleur sur les deux architectures, cela laisse rêveur quant à la soi-disant rapidité des processeurs Motorola, non ? Précisons tout de même que les écarts effarants en vitesse d'affichage viennent aussi du fait que l'affichage de texte sous MS-DOS utilise un "vrai" mode texte, alors que l'on est toujours en mode graphique sur Amiga.
Quoiqu'il en soit, le compilateur GfA permet de générer des programmes rapides et autonomes. Allié à la souplesse de l'interpréteur, il permet de développer efficacement un grand nombre d'applications sans avoir besoin de recourir au C ou à l'assembleur, et surtout en beaucoup moins de temps. Dernier atout, et non des moindres, écrire un programme en GfA-Basic est maintenant un gage de portabilité vers le monde PC, ce qui pourra tenter un certain nombre de développeurs soucieux de rentabiliser leur travaux...
Micro-Application
58 rue du Fauboura-Poissonnière 75010 Paris Tel : 47-70-32-44 “
28. 6
9. 0
Vous avez été nombreux à répondre à notre sondage du numéro 20 de n’ANT. Phis de 300 réponses nous sont parvenues, ce qui représente, en arrondissant un peu, un dizième des abonnés. Le dépouillement fut dur, mais voici ce qui en ressort.
- vos rubriques préférées sont, classées par ordre de préférence : ExecBase, SubWAY, AMOS, Le Coin des Demo-Makers. L'Utilitaire du Mois, Requester, Concours Listing Permanent. ToolBox, L’Invité du Mois, News, Forum, Le Club Dorothée (on s’en doutait).
- 72% des réponses ont cité les News et l’Invité du Mois comme leur semblant carrément de trop dans le journal, argumentant d'ime part, que d’autres revues, dont Amiga Revue, avaieiudéjà des News, et d'autre part que l’on apprécie plus un programmeur pour son travail que pour la couleur de ses chaussettes.
- 63% des réponses demandent l'apparition d’iaie rubrique sur Arexx ; 49% l’extension de la rubrique AMOS et seulemet 12% l’apparition d’une rubrique sur le GfABasic. Les a 'is sont équitablement partagés entre ceux qui souhaitent se voir développer le côté programmation système (48%) et ceux qui souhaitent que l’on accorde une plus grande place à la programmation hardware (51%).
- personne n 'a trouvé l’âge du capitaine C, qui était de 23 ans. Il fallait prendre en compte que la version 1.3 du système inclut la version 34.5 du KickStart et que j’ai mangé chinois hier soir.
- une seule personne, dont je tairai publiquement le nom, à trouvé Denise "rigolotte" ; tous les autres ont répondu "hein ?".
- 35% des lecteurs s'appellent Frédéric, 28%, Philippe, 25%, Denis, 3%, Xavier et un seul, Gwenuël. On avait oublié de demander l'âge, tant pis pour nous.
- la majorité des lecteurs (53%) ont choisi ’abonnement à 5 mois ("pour voir") plus disquette ("parce que je suisfainéant"). 40% om choisi la formule à II mois ("pour vous supporter") sans la disquette ("parce que c’était trop cher"). Personne ne lis le journal chez un copain et ne copie sa disquette !
- l’avis sur la première disquette est majoritairement négatif. Les lecteurs que j’ai pu avoir au téléphone depuis étaient nettement plus satisfaits de la seconde (mais moins que de la troisième, j'espère).
- enfin, une écrasante majorité (78%) possède un Amiga 500, dont 85% avec me extension mémoire, 69% avec un second lecteur et 17% avec un disque dur. 20% d’entre vous possèdem un Amiga 2000, dont 93% avec extension mémoire (jusqu’à 5 Mo), 8% un second lecteur et 89% un disque dur. Enfin, un seul possède un A3000-33. Et personne avant répondu au sondage ne possédait d'Amiga 1000!
Qu allons-nous faire de ceci ? Vous en avez un premier exemple entre les mains : en attendant d’avoir plus de pages (un regret qui revient souvent dans vos lettres), le Concours Listing donnera la préférence aux routines s'attaquant au hardware. Les News ne seront plus qu’épisodiques, si l’actualité le justifie. Quant à l'Invité du Mois, tious le renvoyons à ses foyers repriser ses chaussettes et nous pondre d’autres excellents softs...
LES GAGNANTS
Mais voici venu le moment que vous attendiez tous : trois heureux veinards parmi tous ceux qui ont répondu, ont gagné 5 heures de connection en 3614 sur le serveur Minitel de TANT (pour l’instant et en attendant le 3615 ANT, composer le 3615 COMREX', rubrique ANT). Il s’agit d’Antoine DUBOURG de Dradignan, d’Enzo CUSTODERO de Lyon Sème et de Thierry DELACOUR de Seloncourt Ils sont tous trois cordialement imités à entrer en contact avec la rédaction pour les modalités d'usage, au (1).42.46.92.90 (demander Stéphane).
Isi i&mvê*
Après Vexcellent compïltateur C de Matt Dillon, DICE, et suite aux résultats du sondage, où vous êtes nombreux à nous demander de parler du langage Pascal, je vous propose ce mois-ci une étude d’un compilateur Pascal du Domaine Public dénommé PCQ.
Le compilateur dont j’ai testé la version 1.1c disponible sur la disquette Fish 339, vous sera bien entendu proposé sur la disquette ANT accompagnant ce numéro. La procédure à
• suivre pour le décompactage et l’installation de PCQ n'est pas vraiment difficile, comme vous l’allez pouvoir constater. Tenez donc prêtes deux disquettes, l’une servira à décompacter les fichiers nécessaires (l’utilitaire de décompression, LHArc, est fourni), la seconde servira à l’installation à proprement parler. Pourquoi deux disquettes ? Tout simplement parce que le programme complet tel qu’il a été fourni a Fred Fish (incluant les diverses documentations) occupe plus de 570 Ko ! A moins que vous ne disposiez de suffisamment de mémoire (13 voire 2 Mo) pour utiliser le Ram Disque ou un disque dur. Il est nécessaire d’utiliser une disquette temporaire.
INSTALLATION
Vous trouverez sur la disquette ANT22 un répertoire nommé PCQ. Dans lequel se trouvent trois fichiers, archivés avec LHArc et nommés PCQ.lzh. Runtime.lzh et Source.lzh. Le programme LHArc se trouve quant à lui dans le répertoire ANT22:c (contrairement à la disquette ANT21, où il se trouvait dans le même répertoire que DICE. Ceci pour être en conformité avec la philosophie d'AmigaDOS).
La procédure est donc simple, même si elle peut sembler assez longue. Formatez la première disquette et baptisez-la TEMP. Ensuite, tapez sous CLI les commandes suivantes :
cd TEMP:
ANT22 :c IHArc -x -a -m x ANT22:PCQ PCQ.lzh
à la suite de quoi votre disquette TEMP: contiendra les répertoire suivants :
TEMP: PCQ (dir)
TEMP:A68K_Docs (dir)
TEMP:Blink_Docs (dir)
TEMP:Examples (dir)
TEMP:Include (dir)
TEMP:test_pcq (dir)
Il nous faut maintenant une copie de la disquette Workbench standard. La commande "Duplicate" du menu Workbench fera cela très bien. A la fin de la copie, renommez la nouvelle disquette en PCQ.
Si vous possédez un disque dur. Cette étape n'est évidemment pas nécessaire. Contentez-vous de créer un répertoire PCQ sur votre disque dur. Et assignez-le en PCQ: comme suit (en supposant que votre disque dur se nomme DHO:) :
makedir EH0:PCQ assign PCQ: EH0:PCQ
Par la suite, il sera utile d'inscrire cette commande assign dans votre Startup-Sequence.
Il nous faut maintenant de la place sur notre disquette PCQ pour installer le compilateur Pascal et ses fichiers annexes. Pour ce faire, nous allons détruire les répertoires suivants (avec leur contenu) : Utilities. Empty. Expansion et Prefs. Ces répertoires étant dotés d'une icône, la commande "Discard" du menu "Workbench" fera cela très bien.
Maintenant, ouvrez un Shell et allez sur PCQ: en tapant "cd PCQ:", puis détruisez le répertoire Fonts en tapant "Delete Fonts ALL".
Pour pouvoir continuer à trvailler dans des conditions correctes (c'est-à-dire sans avoir à jouer les grille-pains), nous allons copier un certain nombre de commandes du répertoire c: vers le ram-disque :
COMPILATEUR
c copy c copy ram: c copy c makedir ram: c cqpy c cd ram: c copy c info ram: c copy c dir ram: c copy c delete ram:
On ajoutera un chemin de recherche pour ces commandes à l'aide de "c path ram: ADD".
Maintenant, insérez à nouveau la disquette TEMP dans votre lecteur et tapez la suite de commandes que voici :
copy TEMP:pcq blink PCQ:c copy TatP:pcq a68k PCQ:c copy TEMP:pcq pascal PCQ:c copy TEMP:pcq pcq.lib PCQ: makedir PCQ:Include
copy TEMP:PCQ Include PCQ:Include ail quiet
Voilà pour le dé-archivage et la copie des fichiers. Li ne vous reste plus qu'à éditer la Startup-Sequence de la disquette PCQ: (avec Ed. Memacs ou un autre éditeur de votre choix), pour y remplacer la ligne
path ram: c: sys:utilities sys:sytem s: sys:prefs add
par
path ram: c: sys:System s: add
(ceci afin de tenir compte de la suppression des répertoires Utilities et Prefs).
Encore un dernier effort : éditez également le fichier Shell-Startup de PCQ:. Pour y ajouter la commande "stack 10000". Pour ajouter un peu de pile système pour le compilateur, l'assembleur et le linker. Ceci vous mettra à l'abri de certains plantages bizarres du compilateur...
C'est maintenant fini ! Vous pouvez achever votre oeuvre en créant un répertoire "source" sur la disquette PCQ:, où vous pourrez stocker vos sources Pascal.
OUF!
Si tout c’est bien passé vous devriez avoir dans la disquette que vous avez installée, trois programmes supplémentaires dans le répertoire c: (à savoir "Pascal”. "A68k" et "Blink"), un de plus sous la racine ("pcq.lib") et un répertoire Include contenant tous les includes nécessaires à la programmation sur Amiga.
C'est parti : réinitialisez l'Amiga. La disquette PCQ: étant bien entendu dans le lecteur 0. Puis ouvrez un Shell.
Commençons sans plus attendre par un petit exemple : il s’agit de mettre en pratique les enseignements dispensés lors de mon dernier article sur Intuition. Nous allons en effet ouvrir une fenêtre Intuition et tracer une série de cercles concentriques dans cette fenêtre.
Program Circle;

Programme de tracé de cercles en PASCAL (test de PCQ)
Utiliser le script PL pour cccpiler et linker
Herr Doktor Von GlutenStimnelImDorf, 1991
)
$ 1 "PCQ:Include Bcec.i"}
$ 1 "PCQ:Include Ports.i"}
$ 1 "PCQ:Include Xntuition.i"}
$ 1 "PCQ:Include Graphics.i")
var
fenetre : WindowPtr;
coucou : MessagePtr;
rp : RastPortPtr;
i : integer;
Functioa ouvrfenetre() : Boolean; vax
nouvfenetre: NewWindcwPtr;
begin
new(nouvfenetre); with ncuvfenetreA do begin LeftBdge := 0;
TopEdge := 0;
Width := 640;
Height := 200;
DetailPen := -1;
BlockPen := -1;
HXMPFlags := CLOSEWINDCW_f;
Flags := WINDCWSIZIN3_f + VŒNDOWDRAG_f +
PASCAL "DP" : PCQ ParHDR...p n
WINEOMEEPIH_f + VOŒCWCLOSE_f + 2®HT_REFRESH_f + ACTXVATE_f ; FirstGaâget := nil;
CheckMark nil;
Title := "One fenecre ouverte par PCQ !";
Screen := Nil;
BitMap := nil;
Minwidth := 50;
MaxWidth := -1;
MinHeight := 20;
MaxKeight := -1;
Wtype := WBENCHSCREËN_f; end;
fenetre := OpenWindow(nouvfenetre); dispose(nouvfenetre); ouvrfenetre := fenetre > nil; end;
begin
GfxBase := OpenLibrary("graphies.library", 0); if GfxBase > nil then begin if ouvrfenetre() then begin rp := fenetre'.RPort; for i:= 2 to 45 do
DravCircle(rp, 320, 105, i*2); couccm := WaitPort(fenetre*.OserPort);
Forbid;
repeat
ccxicou ;= GetMsg ( fenetre* .UserPort) ; until coucou = nil;
CloseWi ndow ( fenetre);
Permit;
end
else
writeln('je n arrive pas à ouvrir la fenetre');
CloseX,ibrary(GfxBase) ;
prwi
else
Writeln('Je n'arrive pas à ouvrir la bibliothèque graphique'); end end.
Avant de voir comment compiler et linker ce petit exemple (que vous trouverez sur la disquette ANT22 dans le répertoire TEST_PCQ), j'ai quelques remarques à faire concernant ce programme. D'abord vous remarquerez que sa structure est en tous points similaire à celle du programme C correspondant. C’est normal, puisque les deux langages de programmation sont trcs voisins. Ensuite les fichiers Includes sont de la forme " SI "PCQrlnclude include.i" }". Où include.i représente le fichier à importer. Il vous faudra donc bien préciser dans cette directive le chemin exact où trouver les fichiers, sinon le compilateur générera une erreur. Enfin, je vous conseille d'aller regarder de près les fichiers Includes. Qui sont spécifiques au Pascal. Ainsi, en étudiant de près leur structure (et en regardant la documentaüon. Bien entendu), vous pourrez créer vos propres fichiers pour les bibliothèques de foncdons de votre choix. A titre d'exemple, voici un extrait de l'Include Exec.i.
Function OpenLibraxyd : String; v ; Integer) : Address; external;
Function OpenResource(r : String) ; Address; extemal ;
Procédure Permit; extemal;
Function RemHeadd : Address) : Address; extemal ;
COMPILATION
Maintenant que vous avez tapé (ou copié) ce programme et que vous l'avez sauvegardé, par exemple dans le répertoire source de la disquette PCQ: sous le nom de test.p, vous allez pouvoir le compiler, l'assembler et le linker pour en faire un exécutable. Commençons par le compilateur.
Pascal, le compilateur simple passe, convertit un source Pascal en source assembleur. La directive de compilation est des plus simples, puisqu'il suffit de taper "Pascal source> destination> [ -q>]". L'option -q limitant le nombre de messages envoyé par le compilateur, aux seuls messages d'erreur. Pour compiler notre exemple, nous taperons :
Pascal PCQ:S(Xirce test.p ram:test.asm
Une fois le programme compilé sans erreur. Pascal a généré en ram: un source assembleur tout-à-fait éditable et modifiable. En examinant ce code assembleur, on pourra certes dire qu'il n’est pas réellement optimisé, mais ceci me semble normal dans la mesure où le compilateur étant simple passe, l'optimisation du code généré est difficile. De plus, l'écriture d'un compilateur n'étant pas chose aisée, ne jetons pas la pierre à l'auteur. Et puis à ce prix, trouvez-moi quelque chose de mieux...
Il faut maintenant assembler le source assembleur généré pour créer un fichier objet, l'assembleur proposé est le très célèbre a68k. Qui est l'un des meilleurs dans la catégorie Domaine Public.
Sans rentrer dans le détail des options proposées, nous allons nous contenter d'assembler l'exemple en tapant :
a68k ram:test.asm ram:test.o
Le fichier objet doit maintenant être linké, et c'est là qu'intervient le troisième programme que nous avons copié, Blink. Il ne s'agit pas du célébré linker du lattice sas_c. Mais d'un linker du domaine public. Nous allons utiliser pour cela la syntaxe suivante :
blink ram:test.o to pcq:source test library PCQ:pcq.lib
et vous avez maintenant un exécutable dénommé "test", que vous allez vous empresser de lancer. Pour automatiser le tout, il vous faudra créer un petit script AmigaDOS. L'auteur nous en fournit un d'exemple qui remplit totalement son rôle. Le voici un peu remanié afin de l'adapter à la disquette que nous avons créée.
.key Source A
Pascal Source>.p t: Source>.asm
a68k t: Source>.asm t: Source>.o
Blink t: Source>.o to Source> library pcq:PCQ.lib
delete t: Source>.(asmlo)
Il se trouve dans le répertoire TEST_PCQ. Sous le nom de PL.
Rappel : si vous créez votre propre Script, n'oubliez pas de positionner le bit s (pour script) par la commande "protect +s nom_du_fichier>". Ceci vous évitera de le lancer par la commande execute.
LE RESTE
Que reste-t'il sur cette disquette que nous n'ayons point vu ? Quelques fichiers texte d'abord. Ce sont :
- readme.PCQ : une lettre de fauteur expliquant brièvement ce que fait PCQ ainsi que la liste des fichiers associés :
- Pascal.doc : la documentation du compilateur Pascal ;
- A68k.doc : la documentation concernant l'assembleur ;
- Blink.doc : la documentation permettant d'utiliser le linker ;
Deux fichiers séparés :
- Runtime.lzh contient le source en assembleur de la bibliothèque de fonctions PCQ.lib
- Source.lzh contient les sources du compilateur, écrits eux aussi en Pascal. A ce sujet, vous pouvez en faire l'expérience, il se compile lui-même, d'ou la grave question : comment a fait fauteur (ca me rappelle une histoire de poule et d'oeuf, tout cela) ?
Enfin le dernier fichier. Make.CED. est un fichier Arexx écrit pour les possesseurs de Cygnus Editor. Qui permet de compiler, assembler, linker et corriger les erreurs directement depuis l'éditeur, en appuyant sur quelques touches. L'ensemble de la documentation fournie par fauteur est malheureusement écrite en anglais, mais rassurez-vous, d'un niveau très compréhensible.
En conclusion, d'abord deux mots sur fauteur. Il se nomme Pat Quaid et son adresse, si vous voulez le contacter, est disponible dans le fichier readme.PCQ. Ce programme peut être librement distribué, pour peu que tous les fichiers listés dans readme.PCQ soient présents sur le support de distribution. Enfin, dernier point, le compilateur possède une icône. Cette icône est juste là pour des facilités de copie, et ne permet en aucun cas de lancer le compilateur depuis le Workbench. CLI obligatoire !
Globalement, il s'agit d'un excellent produit, et les essais que j'ai pu faire ont été très concluants. Il est à noter que ce produit fonctionne sur un A3000 (sauf un exemple, fourni sur la disquette, qu’il a refusé obstinément de compiler pour d'obscures raisons). Celà dit, il se présente comme un moyen peu onéreux de s'essayer au Pascal et à la programmation structurée.
Herr Doktor von Glupa a du niai à se compiler lui même ! | j|
L’autre jour, poussé par une impulsion aussi soudaine qu’irrésistible, je décide de me promener incognito sur SGT FLAM. Et là qu ’y vooââ-je ? La fonction drand48() du Lattice 5.04 serait beuuuggguée ?
Secoué par ma compassion légendaire, mon sang ne fait qu’un tour, j'enfile ma rutilante combinaison de pourfendeur d'ignobles bugs gluants, m'arme de ma bombe gourouticide à la citronnelle fermentée et de mon laser à bouchon pour voler chevaleres- quement à votre secours en poussant un cri des plus terrifiques : destroy !
Note : Frédéric étant apparemment plus doué pour la chasse aux bugs que pour la publicité, nous tenons à insérer ici un petit encart particulier à l'attention de Sergent Flam. Comme seulement un nombre réduit d'entre vous doit l'ignorer. Sgt Flam est un serveur RTC (c'est-à-dire fonctionnant sur le réseau téléphonique et non sur Transpac), accessible au 39.55.84.59. Au sommaire : forums, messageries, et surtout des tonnes d’infos de diverses provenances rien que pour les développeurs. Matériel nécessaire : un minitel, c'est tout !
SITUONS LE PROBLEME
Avec ce petit programme appelé drand.c, voyons ce qui ce passe :
“include stdio.h>
include math.h>
void nain ( )

double x=0; inC i=0;
for (i=0;i 19;i++)

x=drand48(); printf(n%f",x);
}
Effectivement, ce programme renvoie un gourou. Mais ne nous affolons pas car si ce bug la fiche mal, c'est vrai, l'environnement du Lattice permet une correction rapide.
11 s'agit d'un gourou N:4. Qui correspond, pour le 68000. à une instruction illégale. Pratiquement, ce type de gourou se rencontre principalement lors d’un mauvais traitement de la pile qui fait que le programme "saute” n'importe où. Le problème de l'instruction illégale apparaissant généralement lui. Lors d'un assemblage, mais pas lors d’un essai.
IDENTIFICATION DU BUG
Compilons et linkons notre petit programme comme ceci
le -d3 -Ima
afin de pouvoir le passer au débuggeur. Qui soit dit en passant, fonctionne très bien, lui :
Une fois là. Appuyons sur la touche retum jusqu'à arriver à la ligne "x=drand48();". Il faut maintenant continuer en pas à pas avec les touches Amiga-T mais APRES être passé en mode assembleur. Le débugger du Lattice a l'excellente idée d'afficher dans la fenêtre de dialogue le nom de chaque routine dans laquelle il entre. Il nous suffit de continuer ainsi jusqu’au plantage en ayant seulement soin de repérer le nom de la routine qui plante.
Comme vous le venez, ce nom est le très poétique et évocateur _CXV25. Ne vous y trompez pas, le plantage est à _CXV35 mais PAR L'ENTREE _CXV25
JACTA EST
LOCALISATION DU BUG
C’est donc la routine _CXV25 qui est buggée. Où est-elle ? Puisque le plantage se produit lors du calcul d'un nombre aléatoire, il s'agit d'un bug de la librairie mathématique lcm.Iib. Qui dans cette routine utilise _CXV25 ' Bonne question, je me remercie de l'avoir posée.
Pour le savoir, nous utiliserons un programme de l'environnement di Lattice, oml. Comme ceci :
çrp.1 LIB: lcm.Iib 1
Cette commande "liste” la librairie, ce qui donne :
Lattice Amiga Format Librarian Version 5.05 Copyright 1988 Lattice, Inc.
Library Listing
Module -Symbol Définitions ------------
atan2.c
_atan2
atof.c
_atof
cosh.c
_cosh
cxa55
_CXS55
_CXA55
cxadj4
_CXADJ4
cxadj5
_CXADJ5
cxc55
_CXC55
cxd55
_CXD55
cxferr.c
_CXFERR
cxfxt5
CXFNM5
_CXFXT5
cxm55
_CXM55
cxn5
_CXN5
cxnravi
_CXNRM4
_CXRTN4
cxnrm5
_CXNFM5
CXTAB5
cxren4
_CXREN4
cxren5
_CXREN5
cxspc4
_SFTieee
_SPFieee
cxspc5
_CXZER5
_CXOVF5
cxt5
_CXT5
cxv34
_CXV34
_CXV24
cxv35
_CXV25
_CXV35
cxv43
_CXV43
_CXV42
Le listing ci-dessus est bien entendu partiel. Si vous examinez cec: attentivement, vous verrez que _CXV25 est appelée par le module cxv35. Ei uniquement par lui. Comme vous pourrez le vérifier en examinant le total s ça vous amuse.
CAPTURE DU BUG
Il faut tout d'abord faire impérativement une copie de votre Lattice origina pour essayer la suite. Je décline toute responsabilité en cas de maladresse sur l'original. Non mais.
Pour gagner du temps lors des manipulations, faites d'abord :
ccpy LIB:lcm.Iib ram: suivi de cd ram:
Bien. Maintenant, nous allons extraire le module cxv35 par :
cml ram:lcm.Iib x cxv35.
Nous avons maintenant en ram: (c'est à ça que servait cd ram:), un fichiei nommé cxv35.o. qui est un fichier objet qu'il nous faut désassembler par :
errd >ram:cxv35.asm cxv35.o
Voici le contenu de cxv35.asm. résultat de cette opération (voir tableau).
Explication de la chose. Tout d'abord, ce module définit pour l’éditeur de liens les labels _CXV25 et _CXV35. C'est cela que signifie "extemal définitions". Où se situent ces labels ? Facile. La colonne de gauche nous donne un offset depuis le début du module. On comprends alors que _CXV25 est à l'offset 0 et _CXV35 est à l’offset 8. De même, le BRA.W 0020 de la troisième ligne du programme (colonne de droite) ne saute pas à l'adresse 20 de l'ordinateur mais à ligne CMPI.L 00200000.EX correspondant à l'offset 20.
La colonne du milieu ne nous intéresse pas, c’est le code machine.
Nous voyons également, troisième ligne en partant de la fin. Que ce module utilise la fonction _CXNRM5. Ce qu'il ne faudra pas oublier plus tard.
Lattice AMIGA 68000-68020 OBJ Msdule Disassembler V5.04.039 Copyright 1988, 1989 Lattice Inc. Ail Rights Reserved.
68000 Instruction Set
_CXV25 0000-00
_CXV35 0008-00
SECTION 00 "text" 00000050 BYTES 1 0000 7800 1 0002 7200 I 0004 6000 001A 1 0008 48E7 3C40
MOVEQ
MOVEQ
BRA.W
MOVOÏ.L
00,D4 00,D1 0020
D2-D5 A1, - (A7)
1 oooc 1 000E 1 0010 ! 0012 ! 0016 1 001A
7800
7200
4A80
6700
6A00
383C
0034
0008
8000
MOVEQ
MOVEQ
TST.L
BEQ.W
BPL.W
MOVE.W
00. D4 00,D1 D0 0048 0020
8000,D4
1 0020
0C80
6400
0020 0000
CMPI.L
00200000,D0
4120,05
1 0025 1 0032
4EBA
4CDF
4E75
3200
4240
4840
0000-XX.1
023C
JSR
MOVEM.L
CXNRM5(PC) (A7)+,D2-D5 A1
1 0038 1 003A 1 003C
MOVE.W
CLR.W
SWAP
D0.D1
D0
D0
! 0040 1 0044 1 0048 1 004C
3A3C
4EBA
4CDF
4E75
4220
0000-XX.1
023C
MOVE.W
JSR
MOVEM.L
RTS
4220,05 _CXNRM5(PC) (A7)+,D2-D5 A1
Examinons d'un oeil de lynx ce trepelu listing. Lorsqu'on entre par _CXV25 (offset 0), les registres D4 et D1 sont initialisés puis on saute à l’offset 20. Suivent alors quelques instructions, l'appel de _CXNRM5. Ensuite on dépile et on sort.
Pa
r
F.
azué
I
13
J'ai dit on dépile ?!? $ &?. Mais, tonnerre, on avait empilé quoi ? Et bien on avait rien empilé du tout et voilà donc le bug.
EXTERMINATION IMPITOYABLE DU BUG
Il n'y a maintenant plus qu’à réécrire le module en tenant compte de tout ce que nous avons vu à propos des labels et des offsets. En ajoutant l’instruction d'empilage qui manque et en faisant très attention au fait que toutes les valeurs numériques du module désassemblé sont exprimées en hexadécimal et donc qu’il faudra, par exemple, remplacer un MOVE.W 8000,D4 par MOVE.W S8000.D4 afin de ne pas générer nous mêmes d'autres bugs (ça serait le comble hein ?)
Voilà le listing, appelé cxv35.a écrit pour Asm du lattice. J'ai choisi Asm pour des questions d'homogénéité avec le reste de l'article, mais n'importe quel macro-assembleur convient (Seka ne fait pas le poids).
- Patch pour la fonction cxv35 du lattice 5.04
- --cette routine est appelée par drand48() et erand48()
- --Assembleur: Asm du Lattice
- --Auteur: F MAZUE pour ANT le 09 01 91
csect
"cxv35",0
XREF _
.CXNRM5
XDEF _
CXV25
XDEF _
.CXV35
MOVEM.L D2-D5 A1,-(A7)
MOVEQ
$ 00,D4
MOVEQ
$ 00,D1
BRA.W
label1
MOVEM.
,L D2-D5 A1, - (A7)
MOVEQ
$ 00, D4
MOVEQ
$ 00, D1
TST.L
D0
BEQ.W
label3
BPL.W
label1
MOVE.W
$ 8000,D4
CMPI.L
$ 00200000,D0
BCC.W
label2
MOVE.W
$ 4120,D5
JSR
_CXNRM5 (PC)
MOVEM.L
(A7)+,D2-D5 A1
RTS
MOVE.W
D0,D1
CLR.W
D0
SWAP
D0
SWAP
D1
MOVE.W
$ 4220,D5
JSR
_CXNRM5(PC)
MOVEM.L
(A7)+,D2-D5 A1
RTS
END
Il reste à assembler ceci on ne peut plus simplement par : asm cxv35
et l'on obtient en ram: un nouvel objet cvx35.o qu'il faut maintenant insérer dans la librairie, opération qui écrasera l'ancien module buggé. Ceci se fait par :
anl ram:lcm.lib r cxv35.o Sauvegardons enfin notre travail :
copy ram:1cm.lib LXB:
Et nous aurons la joie de constater que le programme recompilé drand.c du début fonctionne cette fois parfaitement.
Du même coup, la fonction erand48 est elle aussi debuggée.
PETIT COMPLEMENT A PROPOS DE ERAND48
Le programme drand.c a le défaut de sortir à chaque appel la même série de nombres aléatoires. Pour varier les résultats, il faut utiliser la fonction erand48. Cette fonction calcule les nombres à partir du contenu d’un tableau. Si vous modifiez le contenu du tableau, les résultats obtenus par erand48 seront également modifiés.
Mais attention, le tableau doit être ainsi défini comme "unsigned short seed[3]" et non pas "short seed|3J". Comme dit dans la notice. En fait, cette coquille est corrigée dans l'crrata de l'addendum. Mais je me suis permis de vous le signaler car cette information passe, semble-t-il. Souvent inaperçue.
Voici un programme uülisant erand48 et initialisant le tableau sur le temps système.
include stdio.h>
Sinclude math.h>
void main( )

unsigned short seed[3); dcxible x=0; int i=0;
seed[2] = (unsigned short)t ime() seedïl] = (unsigned short)time(} seed[0] = (unsigned short)time()
for (i=0;i 19;i++)

x=erand48(seed); printf(x);
}
Pour ceux qui désireraient exactement connaître comment sont tirés des nombres aléatoires, sachez que ceci est une autre histoire...
Frédéric MAZUE n’est pas soumis aux aléas du short
Désolé pour les amateurs de bla-bla, mais nous attaquons sans plus tarder notre passage en revue des instructions du MC68000...
LE 68000 DE A à Z
Dans la liste qui suit, l’on décrit les instructions par ordre alphanumérique croissant, en précisant l’opération effectuée, la ou les syntaxes possibles, la ou les tailles autorisées, le codage en mémoire de l’instruction (seul le code opératoire sur 16 bits est décrit ; des données supplémentaires, jasqu’à 10 octets en tout, peuvent apparaître pour certaines instructions) et les flags du registre de conditions (CCR) affectés. Presque toutes les instructions font appel à la notion d’adresse effective (notée ea> pour " effective addrcss>"). Il s'agit du ou des modes d'adressages autorisés. Codé(s) sur 6 bits, d'après le tableau paru dans la rubrique ExecBase du mois dernier (ANT numéro 21. Page 7). Evidemment, toutes les instructions n'autorisent pas tous les modes d'adressages.
Les instructions conditionnelles (Bcc. Dbcc. Scc) codent la condition sur 4 bits, d’après le tableau suivant.
Code
Condition
0000
F (false)
0001
T (vrai)
0010
m
(high)
0011
LS
(Less or Same)
0100
CC
(Cary Clear)
0101
es
(Cary Set)
0110
NE
(Not Equal)
0111
EQ
(EQual)
1000
VC
(overflcw Clear)
1001
VS
(oVerflow Set)
1010
PL
(PLus)
1011
MI
(Minus)
1100
GE
(Greater or Equal)
1101
LT
(Less Than)
1110
GT
(Greater Than)
1111
LE
(Less or Equal)
DDE : 011=opération sur un mot (étendu à 32 bits) lll=opération sur un long affectés
Flags
ADDI (addition binaire immédiate)
Syntaxe AUDI Sdonnée, ea>
Taille Octet, mot, mot long
Format 15 14 13 12 11 10 09 0000011
07 06 05 04 03 02 01 00
TAILLE ADRESSE EFFECTIVE
TAILLE : 00=OCtet, 01=mot, 10=long
La donnée est codée dans le mot (TAILLE=00 ou 01 ) ou dans le mot long (TA1LLE=10) suivant le code opératoire.
FlagS N : 1 si résultat négatif, 0 sinon
Z : 1 si résultat nul, 0 sinon
V : 1 si débordement, 0 sinon
C : 1 si retenue, 0 sinon
X : idem C
ADDQ (addition binaire immédiate rapide)
Syntaxe ADDQ donnée, ea>
Taille Octet, mot, mot long
11 10 09
08
07 06
DONNES
0
TAILLE
AIRESSE EFFECTIVE
de 000 à 111 (000=8)
codage de la donnée inmédiate, TAILLE : 00=octet, 01=mot, 10=long N : 1 si résultat négatif, 0 sinon
Flags
Z : 1 si résultat nul, 0 sinon
V : 1 si débordement, 0 sinon
C : 1 si retenue, 0 sinon
X : idem C
Si l'addition concerne un registre d restent
ADDX (addition binaire avec le bit d’extension)
ABCD (addition décimale avec le bit d'extension)
Sxniaxe abcd dx, Dy
ABCD -(Ay),-(Ax)
Taille Octet
Format 15 14 13 12 1100
11 10 09 Rx
08 07 06 05 04 03 1 0 0 0 0 M
02 01 00 Ry
Rx : registre source (0-7)
Ry : registre destination (0-7)
M : Mode (0=registres de données
FlügS N : indéfini
Z : 0 si le résultat est non nul, C : 1 si une retenue est générée, X : idem C
ADD (adition binaire)
=registres d'adresse)
inchangé sinon 0 sinon
Syntaxeadd ea>,Dn ADD Dn, ea>
Taille Octet,
mot.
Net
long
Format 15 14 1 1
13
0
12
1
11 10 09 REGISTRE
08 07 06 OP-MODE
05 04 03 02 01 00 ADRESSE EFFECTIVE
REGISTRE : numéro du registre de données (0-7) OP-MODE : Octet Mot Long
000 001 010 (syntaxe 1)
100 101 110 (syntaxe 2)
FlagS N : 1 si le résultat est négatif, 0
Z : 1 si le résultat est nul, 0 sinon
V : 1 si débordement, 0 sinon C : 1 si retenue, 0 sinon X : idem C
ADDA (addition binaire avec registre d’adresse)
Syntaxe adda ea>,An Taille Mot, mot long
C= AMIGA NEWS-TF.CH IL! NTMERO 22 MAI 1991
Formai 15 14 13 12
11 10 09
08 07 06
05 04 03 02 01 00
1101
REGISTRE
OP-MODE
ADRESSE EffECrxVE
REGISTRE : numéro du registre d'adresse (0-7)
S 71ta.xe ADDX Dx, Dy
ADDX -(Ay),-(Ax)
Taille octet.
Mot.
Mot
long
Format 15 14 1 1
13
0
12
1
11 10 09 Rx
08
1
07 06 TAILLE
05 04 03 0 0 M
02 01 00 Ry
M : 0=registres de données, l=registres d'adresse TAILLE : 00=octet, 01=mot, 10=long N : 1 si résultat négatif, 0 sinon
Flags
Z : 1 si résultat nul, inchangé sinon
V : 1 si débordement, 0 sinon
C : 1 si retenue, 0 sinon
X idem C
AND (et logique)
Syntaxe and ea>,Dn and En, ea>
Taille octet.
Mot.
Mot
long
Fonnat 15 14 1 1
13
0
08 07 06 OP-MDDE
0
REGISTRE
ADRESSE EFFECTIVE
REGISTRE : numéro du registre de données (0-7) OP-MDDE : Octet Mot Long
000 001 010 (syntaxe 1)
100 101 110 (syntaxe 2)
Flags N : 1 si résultat négatif (MSB=1), 0 sinon Z : 1 si résultat nul, 0 sinon V : toujours 0 C : toujours 0 X : inchangé
ANDI (et logique immédiat)
Syntaxe ANDI donnée, ea>
Taille octet, mot, mot long
Format 15 14 13 12 11 10 09 08
07 06
05 04 03 02 01 00
00000010
ADRESSE EFFECTIVE
TAILLE : 00=octet, 01=mot, 10=long
La donnée est codée dans le mot (TAILLE=00 ou 01 ) ou dans le
mot long (TAILLE=10) suivant le code opératoire.
Flags N : 1 si résultat négatif (MSB=1), 0 sinon Z : 1 si résultat nul, 0 sinon V : toujours 0 C : toujours 0 X : inchangé
ANDI to CCR (et logique immédiat avec CCR)
Taille Octet, mot long
Format un registre En contient le numéro du bit, modulo 32 :
15 14 13 12 I 11 10 09 108 07 06 I 05 04 03 02 01 00
0 0 0 0 1 REGISTRE 11 0 il ADRESSE EFFECTIVE
REGISTRE : numéro du registre de données (0-7)
Une donnée immédiate indique le numéro du bit :
15 14 13 12 11 10 09 08 07 06 I 05 04 03 02 01 00
0 0 0 0 1 0 0 0 0 il
Syntaxe ANDI donnée,CCR Taille Octet (5 bits)
Format 15 14 13 12 il 10 09 0 0 0 0 0 0 1
38 07 06 05 04 03 02 01 00 000111100
La donnée (8 bits) est codée dans le mot suivant le code opératoire.
Flags
N :
: 0
si
le
bit
3
de
la
donnée
est
0, inchangé
sinon
Z :
: 0
si
le
bit
2
de
la
donnée
est
0, inchangé
sinon
V :
: 0
si
le
bit
1
de
la donnée
est
0, inchangé
sinon
C :
: 0
si
le
bit
0
de
la
donnée
est
0, inchangé
sinon
X :
! 0
si
le
bit
4
de
la
donnée
est
0, inchangé
sinon
ANDI to SR (et logique immédiat avec SR) Instruction privilégiée.
Syntaxe andi
Taille Mot (tous les bits ne sont pas pris en ccnpte)
Format 15 14 13 12 il 10 0 0 0 0 0 0
18 07 06 05 04 03 02 01 00 001111100
La donnée est codée sur 8 bits dans le mot suivant le code opératoire.
Si l’adresse effective est une adresse, seul un octet est concerné.
FlagS N : inchangé
Z : 1 si le bit testé est 0, 0 sinon V : inchangé C : inchangé X : inchangé
BCLR (test et mise à 0 d’un bit)
Syntaxe bclr Dn, ea>
BCLR donnée, ea>
Taille Octet, mot long
Format Un registre En contient le numéro du bit, modulo 32 :
15 14 13 12 I 11 10 09 I 08 07 06 I 05 04 03 02 01 00
0 0 0 0 I REGISTRE 11 1 0 I ADRESSE EFFECTIVE
REGISTRE : numéro du registre de drainées (0-7)
Une donnée immédiate indique le numéro du bit :
15 14 13 12 11 10 09 08 07 06 | 05 04 03 02 01 00
OOOOlOOOlOl ADRESSE EFFECTIVE
La donnée (16 bits) est codée dans le mot suivant le code opératoire.
Flags N : 0 si le bit 3 de la donnée est 0, inchangé sinon
Z : 0 si le bit 2 de la donnée est 0, inchangé sinon
v : 0 si le bit 1 de la donnée est 0, inchangé sinon
C : 0 si le bit 0 de la donnée est 0, inchangé sinon
X : 0 si le bit 4 de la donnée est 0, inchangé sinon
ASL, ASR (décalage arithmétique)
Syntaxe asx Dx,Dy
Asx donnée,Dy Asx ea>
x=L (Left, gauche) eu R (Right, droite)
Taille Octet, mot, mot long
La donnée est codée sur 8 bits dans le mot suivant le code opératoire.
Si l'adresse effective est une adresse, seul un octet est concerné.
FlagS N : inchangé
Z : 1 si le bit testé est 0, 0 sinon V : inchangé C : inchangé X : inchangé
BRA (branchement inconditionnel)
Syntaxe bra iabei>
Taille Octet, mot
Format Décalage d'un registre :
15 14 13 12 1 11 10 09 1 1 1 0 1 NOMBRE
08
D
07 06 TAILLE
05 04 03 10 0
! 02 01 00 1 REGISTRE
Décalage d'une adresse :
15 14 13 12 11 10 09 1 1 1 0 0 0 0
08
D
07 06 1
1 il
05 04 03 02 01 00 ADRESSE EFFECTIVE
de décalages ou numéro du registre de Dx le contenant (2ème syntaxe)
D : 0=décalage droite (ASR), l=décalage gauche (ASL) TAILLE : 00=octet, 01=mot, 10=mot long X : 0=NCMBRE indique le nanbre de décalages (0-7, 0=8), 1=NCMBRE indique le registre contenant le nombre de décalages (modulo 64)
Flags
N : 1 si résultat négatif (MSB=1), 0 sinon Z : 1 si résultat nul, 0 sinon
V : 1 si le MSB est modifié pendant le décalage, 0 sinon C : égal au dernier bit sorti de l'opérande X : idem C
Bcc (branchement conditionnel)
Syntaxe bcc label >
Taille Octet, mot
Format 15 14 13 12 il 10 09
07 *06 05 04 03 02 01 00 DEPLACEMENT (8 BITS)
0 110 CONDITION
Le déplacement sur 8 bits est codé dans le code opératoire. S'il vaut 0, le déplacement sur 16 bits est codé dans le mot suivant le code opératoire.
Flags inchangés
BCHG (test et inversion d’un bit)
Sxntaxe bchg Dn, ea>
Format 15 14 13 12 il 10 0 110 0 0
07 06 05 04 03 02 01 00 BITS)
Le déplacement sur 8 bits est codé dans le code opératoire. S’il vaut 0. Le déplacement sur 16 bits est codé dans le mot suivant le code opératoire.
FlagS inchangés
BSET (test et mise à 1 d'un bit)
Syntaxe bset Dn, ea>
BSET donnée, ea>
Taille Octet, mot long
Format X3n registre Eto contient le numéro du bit, modulo 32 :
15 14 13 12 111 10 09 I 08 07 061 05 04 03 02 01 00
0 0 0 0 I REGISTRE 11 1 il ADRESSE EFFECTIVE
REGISTRE : numéro du registre de données (0-7)
Une drainée immédiate indique le numéro du bit :
15 14 13 12 11 10 09 08 07 06 I 05 04 03 02 01 00
OOOOlOOOllI ADRESSE EFFECTIVE
La donnée est codée sur 8 bits dans le mot suivant le code opératoire.
Si l'adresse effective est une adresse, seul un octet est
concerne.
Flags N : inchangé
1 si le bit testé est 0, 0 sinon
V :
C :
X : inchangé
BSR (branchement à un sous-programme)
Syntaxe bsr iabei>
Taille octet, mot
SUITE PAGE 18
Faire défiler un dégradé digne de ce nom... Mais ne rêvons pas : Vamiga ne possède pas 16 millions de couleurs, mais (seulement ?)
4096. ..
DEGRADE DE COULEURS EN UTILISANT UNE TRAME PAR GURTH POUR ANT
Pour remédier à cela, il suffit de "mixer" les couleurs à l'aide d'une texture (en rapprochant deux pixels de couleurs différentes, on en obtient une nouvelle. Cette méthode est très utilisée dans la synthèse d'image sur Amiga). Pour corser le tout, on fait la chose en Overscan... Enfin, on affiche un logo, par un simple transfert au Blitter. A noter que le logo est constitué d'un seul bitplane de 320 pixels de large (40 octets) sur 92 de haut. 11 n'est donc pas au format IFF. Et est décompacté. Utilisez pour ce faire le Deluxe IffConverter fourni avec DeluxePaint. Ou n'importe quel autre utilitaire de votre choix capable de sauvegarder une imase en format RAW.
LE DEGRADE
On utilise pour le réaliser, une texture (certains préfèrent dire une trame) de 16 pixels de large sur 16 de haut.
Un petit schéma valant toujours mieux qu'un long discours, suivez donc sur le tableau ci-dessous.
Effet
Motif texture oooooooooooooooo ooooooooiooooooo 0000100000001000
16 pixels de couleur 0, 0 de couleur 1
15 pixels de couleur 0, 1 de couleur 1
14 pixels de couleur 0, 2 de couleur 1
SECTION GURTH, CODE_C
M0VE.3
m0000111,$ BFD100
ARRETE LES DRIVES
MOVE.L
4,A6
BASE D'EXEC
JSR -132 (A6)
FORBID, PLUS DE MULTITACHE
MOVE.L
$ 6C,SAVE_VECTEUR_IRQ
MOVE.W
SDFF01C,SAVE_INTENA
SAUVEGARDE DE QUELQUES
OR.W
$ C0 0 0,SAVE_INrENA
CONTENUS D' Addresses
MOVE.W
$ DFF002,SAVEJ34ACON
IMPORTANTS
OR.W
$ 8100,SAVE_EMACON
MOVE.W
%0000010000101111,SDFF096
VIRE SPRITES ET SON
MOVE.W
%1000001111000000, $ EFF096
EMA, BPIEN, BLITTER, COPPER
MOVE.W
$ FFFF,$ DFF0 4
INITIALISATION DES MASQUES
MOVE.W
$ FFFF,SDFF046
UNE BONNE FOIS POUR TOUTES
MOVE.W
$ 0,$ DFF042
MEME CHOSE POUR BLTCON1
MOVE.L
COPPERLIST,$ DFF080
ADRESSE COPPERLIST
MOVE.W
$ 0,$ DFF088
START COPPERLIST
MOVE.L
ECRAN,DO
MOVE.W
DO,PLAN1+6
ON MET
SWAP
DO
MOVE.W
DO,PLAN1+2
L'ADRESSE DES DEUX
SWAP
D0
ADD.L
11968,D0
BITPLANS
MOVE.W
DO,PLAN2+6
SWAP
D0
DANS COPPERLIST
MOVE.W
DO,PLAN2+2
BSR MAKE_COPPER_DEG
CONSTRUIT COPPER_DEGRADE
BSR AFFICHE_LOGO
LEA TEXTURE, A0
LEA TABLE. ..COULEURS, Al
INITIALISE LES REGISTRES
PROG PRINCIPAL
tilUMIlIlltiHEN VOIR DE TOUT
2 pixels de couleur 0, 14 de couleur 1
1111011111110111
1111111101111111
1111111111111111
WAIT COPPER1:
1 pixels de couleur 0, 15 de couleur 1
0 pixels de couleur 0, 16 de couleur 1
- > couleur 0 reçoit couleur 1 et couleur 1 reçoit la prochaine 0000000000000000 16 pixels de couleur 0, 0 de couleur 1
0000000010000000 15 pixels de couleur 0, 1 de couleur 1
... et ainsi de suite jusqu'au bas de l'écran.
Ainsi, toutes les 16 lignes, la texture recommence et les couleurs changent (très peu pour avoir un joli dégradé).
Pour faire défiler ce dégradé, il faut faire remonter la texture et les couleurs ligne par ligne. Une fois remontées de 16 points, il faut faire apparaître de nouvelles couleurs en bas de l'écran en même temps, qu'apparait un nouveau morceau de texture.
OVERSCAN
Un rapide rappel n'est sans doute pas superflu. Quatre addresses et quatre formules sont à retenir pour définir la taille et la position de l'écran.
Pour la position :
CMP.B
$ FF,SDFF006
ON SE SYNCHRONISE
BNE WAIT_COPPERl
AVEC LE SPOT
BSR ANTM_DEGRADE
BTST
6,$ BFE001
BOUTON DROIT DE LA SOURIS ?
BNE WAIT COPPER1
NON ?
MDVE.L
SAVE_VECTEUR_IRQ,$ 6C
MDVE.W
$ 7FFF,$ DFF09A
REMET EN PLACE LES CONTENUS
MDVE.W
SAVE.INTENA,$ DFF0 9A
MDVE.W
$ 7FFF,SDFF096
D'ADRESSES IMPORTANTES
MDVE.W
SAVEJMACON, $ DFF096
MDVE.L
$ 4, A6
CLR.L
D0
LEA. L
GFX_LIB,Al
ON ESSAYE DE TOUT REMETTRE
JSR -552 (A6)
MDVE.L
DO, A0
EN ORDRE
MDVE.L
38(AO),SDFF080
CLR.W
SDFF088
POUR TENTER UNE SORTIE...
MDVE.L
DO,Al
JSR -414 (A6)
ON REFERME GFX__LI3
JSR -138(A6)
ON RETCXJRNE EN MULTITACHE
RTS
- ------ THE END -------
nsYTD&ns*____________________
DTVSTRT ($ DFF08E) BITS: 15-8 VSTART, 7-0 HSTART DIWSTOP ($ DFF090) BITS: 15-8 VSTOP, 7-0 HSTOP
HSTOP+$ 100-HSTART HAUTEUR : VSTOP+(bit 8 de VSTOP *$ 100)-VSTART
Pour la taille :
- DDFSTRT ($ DFF092) Lo-Res : ( (HSTART 2) -8.5) Hi-Res : ((HSTART 2)-4.5)
- DDPSTOP (SDFF094) Lo-Res : DDPSTRT+ ( (nots par ligne-1)*16 2) Hi-Res : DDFSTRT+((mots par ligne-2)*16 4)-
Pour la Copperlist. Une fois arrivé à la ligne $ FF, on recommence à $ 00 après un Wait spécial : Wait(SFFDF.SFFFE).
Philippe Rivaillon, alias Gurth
MAKE_COPPER_DEG:
LEA DEGRADE,A3 MDVE.W $ 1901,DO _MAKB_COP:
MDVE.W D0,(A3)
MDVE.W $ FFFE,2(A3) MDVE.L $ 01800000,4(A3) MDVE.L $ 01820000,8(A3) MOVE.L $ 01840000,12(A3) MDVE.L $ 01860000,16(A3) ADD.L 20,A3 ADD.W $ 0100,DO CMP.W $ 0001,D0 BNE BOOCLE_MAKE_COP MOVE.L $ FFDFFFFE,(A3) ADDQ.L $ 4,A3 _LIGNES:
M0VE.W D0,(A3)
M3VE.W $ FFFE,2(A3)
FONCTION WAIT DU COPPER
DEUX BITPLANS
ON AVANCE...
WAIT LIGNE SUIVANTE FIN ECRAN NORMAL ?
OUI ? SINON BOUCLE NECESSAIRE A LA TRANSITION VERS LES LIGNE DU "BAS"
MEME CHOSE QUE CI-DESSUS
ES LES COULEURS
MOVE.L $ 01800000,4(A3) M3VE.L $ 01820000,8(A3) MOVE.L $ 01840000,12(A3) MOVE.L $ 01860000,16(A3) ADD.L 20,A3 ADD.W $ 0100,DO CMP.W $ 2901,DO BNE DSRNIERES_LIGNES MOVE.L $ FFFFFFFE,(A3) RTS
ATTEND BLITTER
MOVE.L
MOVE.W
MOVE.W
MOVE.W
MOVE.W
RTS
(ZONE DIFFICILE A ATTEINDRE MAIS OVERSCAN OBLIGE...)
FIN DE LA COPPERLIST ENFIN!
MAIS AVEC LES LIC3ΠDO BAS
IMAGE DE 320 92 ECRAN+16370,$ DFF054 ; DESTINATION
%OOOai00111110000,$ DFF04Û ; BLTCONO
0, $ DFF064 ; PAS DE MODULO A LA SOURCE
4,$ DF?066 ; MODULO DEST.=(352-320) 8
5908,$ DFF058 ; TAILLE -> TRANSFERT
AFFICHE. LOGO :
BTST 14,$ DFF002 BNE AFFICHE_LOGO MOVE.L IMAGE,SDFF050
ROUTINE DEGRADE ANIME
"graphies.library",0,0
GFX_LIB: D
COPPERLIST:
DC. W
DC. W
DC. W
PLAN1: DC.W
PLAN2: DC.W
$ 0100,$ 2200,$ 008E,$ 1971 $ 0090,$ 29D1,$ 0092,$ 0030 $ 0094,$ 00D8
$ 00E0,$ 0000,$ 00E2,$ 0000 $ 00E4,$ 0000,$ 00E6,$ 0000
SB BITPLANES, TAILLE ECRAN ETC -> ON DEFINIT L'ECRAN
20(A3),(A3)
24(A3),4(A3) 28(A3),8(A3) 32(A3),12(A3) 20,A3
$ FFDF,-6(A3)
BITPLAN 1 ADRESSE BITPLAN 2
SUITE ET FIN COPPERLIST
DEGRADE: DCB.B 5448,0
; 2 FOIS LE MOTIF DU DEGRADE
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
TABLE_COULEURS:
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
DC. W
FAIT ENTRER UNE NOUVELLE COULEUR
MOVE.W
MOVE.W
MOVE.W
ADDQ.L
CMP.W
SAVE_IOTENA: DC.W 0 SA.VE_DMACON: DC.W 0 SAVE_VECTEUR_IRQ: DC.L 0
DCB.B 23936,0 INCBIN "IMAGE"
ECRAN:
IMAGE:
ANTM DEGRADE:
LEA DEGRADE+6,A3
CIRCULE:
MOVE.W M3VE.W MOVE.W MOVE.W ADD.L CMP.W
BNE CIRCULE ADDQ.L 4,A3 MOVE.W (A3),-24(A3)
MOVE.W 4(A3),-20(A3)
MOVE.W 8(A3),-16(A3)
MOVE.W 12(A3),-12(A3)
CIRC_DERNTERES_LIGNES:
MOVE.W 20(A3), (A3)
MOVE.W 24(A3),4(A3)
MOVE.W 28(A3),8(A3)
MOVE.W 32(A3),12(A3)
ADD.L 20,A3 CMP.W $ 2801,-6(A3)
BNE CIRC.
LEA ECRAN, A3
ADD.L 2,A0
CMP.L TEXTORE+32,A0
BLE WAIT_BLIT1
BSR NOUVEL!,K_COULEUR
SUB.L 32,AO
WAIT_BLIT1:
BTST 14,$ DFF002
BNE WAIT_BLIT1
MOVE.L AO,$ DFF050
MOVE.L A3,$ DFF054
MOVE.W %0000100111110000,
MOVE.W 00,$ DFF064
MOVE.W 42, $ DFF066
MOVE.W 1025,$ DFF058
ADDQ.L 2,A3
CMP.L ECRAN+4 4, A3
BNE WAIT_BLIT1
WAIT_BLIT2:
BTST 14,$ DFF002
BNE WAIT_BLIT2
MOVE.L ECRAN,SDFF050
MOVE.L ECRAN+704,$ DFF054
MOVE.W 0,$ DFF066
MOVE.W 16406,$ DFF058
RTS
NOUVELLE_COULEUR:
MOVE.W (Al),DEGRADE+5430 2(Al),DEGRADE+5434 4(Al),DEGRADE+543 8 6(Al),DEGRADE+5442 $ 2, Al $ FFFF,6(Al)
BEQ REINIT_DEGRAI1E RTS
REINTT DEGRADE :
LEA TABLE_COULEURS+2 8, Al RTS
ON FAIT REMONTER TOUTES LES COULEURS D'UNE LIGNE VERS LE HAUT
ATTENT FIN D'ECRAN NORMAL ATENTIQN! !
LE ' DC.W $ FFDF,$ FFFE '
A FAIT APPARAITRE UNE IRREGULARITE !
CM REPREND LE TRAIN-TRAIN
AVEC LES LIGNES EU "BAS"
AH ? LA FIN DU DECALAGE ?
DECALE LA TEXTURE (SCROLL!) DECALE 16 FOIS ?
NON
OUI, ALONS Y...
FAIT POINTER AO SUR TEXTURE
ATTENT QUE LE BLITTER SOIT DISPONIBLE SOURCE: TEXTURE (-fDECALAGE) DESTINATION : HAUT ECRAN $ DFF040 ; BLTCONO...
PAS DE MODULO A LA SOURCE MOD. DESTINATION 352-16) 8 TAILLE DU TRANSFERT DECALAGE DESTINATION REMPLIR LE HAUT DE L'ECRAN
COULEURS SUR LES DERNIERES LIOJES DE LA COPPERLIST
DECALE POINTEUR COULEURS FIN DE TABLE_COULEURS ?
NON
OUI
ON REPOINTE SUR LE DEBOT EN EVITANT NOIR DU DESOT
UN TRANSFERT SUFFIT PCXJR REMPLIR LE RESTE DE L'ECRAN CAR LE BLITTER TRAVAIL DU HAUT VERS LE BAS LIGNE APRES LISE INITIAL!SE LE
HOOOOOOOOOOOOOOOO
S&0000000010000000
%0000100000001000
%0001000010000100
%0010001000100010
%0010010010010010
%0100100101001001
%0101010101010010
%1010101010101101
%1011011010110110
%1101101101101101
%1101110111011101
%1110111101111011
%1111011111110111
%1111111101111111
%1111111111111111
%0000000000000000
%0000000010000000
%0000100000001000
%0001000010000100
%0010001000100010
%0010010010010010
%0100100101001001
%0101010101010010
%1010101010101101
%1011011010110110
%1101101101101101
%1101110111011101
S&1110111101111011
%1111011111110111
%1111111101111111
%1111111111111111
; COULEURS CIRCULANTES $ 001,$ 002,$ 003,$ 004,$ 005,$ 006,$ 007,$ 008 $ 009,$ 00a,$ 00b,$ 00c,$ 00d,$ 00e,$ 00f,$ 10e $ 20d,$ 30c,$ 40b,$ 50a,$ 609,$ 708,$ 807,$ 906 $ a05,$ b04,$ c03,$ d02,$ e01,$ f00,$ el0,$ d20 $ c30,$ b40,$ a50,$ 960,$ 870,$ 780,$ 690,$ 5a0 $ 4b0,$ 3c0,$ 2d0,$ le0,$ 0f0,$ 0el,$ 0d2,$ 0c3 $ 0b4,$ 0a5,$ 096,$ 087,$ 078,$ 069,$ 05a,$ 04b $ 03c,$ 02d,$ 01e,$ 00f,$ 10e,$ 20d $ FFFF
; 2 BITPLANS DE 352 272 ; 1 BITPLANE DE 320 92
AFFICHAGE DU LOGO
El
Format 15 14 13 12 11 10 09 08
07 06 05 04 03 02 01 00
Le déplacement sur 8 bits est codé dans le code opératoire. S'il vaut 0. Le déplacement sur 16 bits est codé dans le mot suivant le code opératoire.
Flags inchangés
BTST (test d'un bit)
Syntaxe btst e», ea>
BTST foionnée, ea>
Taille Octet, mot long
Format Va registre m contient le numéro du bit, modulo 32 :
15 14 13 12 111 10 09 108 07. 06 | 05 04 03 02 01 00
0 0 0 01 REGISTRE 11 0 0 ! AEKESSE EFFECTIVE
registre : numéro du registre de données (0-7)
One donnée immédiate indique le numéro du bit :
15 14 13- 12 11 10 09 08 07 06 I 05 04 03 02 01 00
OOOOIOOOOOI ADRESSE EFFECTIVE
La donnée est codée sur 8 bits dans le mot suivant le code opératoire.
Si l'adresse effective est une adresse, seul un octet est concerné.
Flags N : inchangé
Z : 1 si le bit testé est 0, 0 V : inchangé C : inchangé X : inchangé
CHK (test de limites)
Instruction privilégiée
Syntaxe chr ea>,nn Taille Mot
Formai 15 14 13 12 0100
11 10 09
08 07 06
05 04 03 02 01 00 MWWfSSB KPFBCTIVE
REGISTRE : Numéro du registre à tester.
Flags N : 1 si En 0, 0 si En > ea>
Z : indéfini V : indéfini C : indéfini X : inchangé
Notes Cette instruction teste les 16 bits de poids faible du
registre spécifié, et déclenche une exception numéro 6 si ce registre est inférieur à 0 ou supérieur à ea>.
CLR (mise à 0)
Syntaxe cia ea>
Taille Octet, mot, mot long
Format 15 14 13 12 il 10 09 0 1 0 0 0 0 1
07 06 05 04 03 02 01 00 0 TAILLE ADRESSE EFFECTIVE
TAILLE : 00=octet, 01=mot, 10=mot long Flags N : 0 Z : 1 V : 0 C : 0
X : inchangé
CMP (comparaison) Syntaxe cmp ea>,m
Taille Octet, mot, mot
long
10 11
REGISTRE OP-MDDE
ADRESSE EFFECTIVE
REGISTRE : numéro du registre de données (0-7) OP-MODE : 000=octet, 001=mot, 010=mot long Flags N : 1 si résultat négatif, 0 sinon
Z : 1 si résultat nul, 0 sinon
V : 1 si débordement, 0 sinon
C : 1 si retenue, 0 sinon
X : inchangé
?
Fi A &
i]
Ce listing est une routine de 3D dite ’jil de fer Cet article se composera de 3 parties : le clipping de droites, astuces générales et les formules mathématiques.
Il arrive parfois quand on joue avec la 3D ou tout autre programme utilisant des droites, que celles ci "sortent" de l’écran, d’où un gros problème : en effet, si l’on n’y prend garde, la droite sera dessinée dans une zone de la mémoire qui n’a rien à voir avec l’écran, effaçant peut-être une partie du programme ou de ses données. Il est donc impératif de faire une routine qui gère ce phénomène. C’est ce que l’on appelle le "clipping" (découpage, en français).
Dans un premier temps, on clippe la droite en y. Pour cela, on fait en sorte que la première coordonnée (xl, yl) ait le plus faible y. Ainsi, si la seconde coordonnée (x2, y2) est au dessus du bord supérieur de l'écran (y_min) OU si la première coordonnée est en dessous de son bord inférieur (y_max), la ligne est totalement invisible. De plus, si la première coordonnée est en dessous du bord supérieur ET la seconde au dessus du bord inférieur, la ligne est visible dans son intégralité (tout du moins en ce qui concerne les y).
Si ces 2 tests sont négatifs, alors il existe une intersection de la droite avec les bords. Si yl y_min. On calcule l'intersection avec le bord supérieur. De même, si y2>y_max. On calcule l'intersection avec le bord inférieur.
Il ne reste plus qu'à exécuter les mêmes opérations pour les coordonnées en
x. Tout le monde utilise plus ou moins cette technique, mais on peut ruser sur la manière de calculer les intersections. Dans le programme, j'utilise la technique dite de "dichotomie". Voici un exemple qui calculera l'intersection entre une ligne de coordonnées Pl(150,20)-P2(400,50) et la droite du bord droit de l'écran (y=320). 150 est inférieur à 320 et 400 est supérieur à 320 donc l'intersection existe. On calcule le milieu de la droite xmil=( 150+400) 2=275 et ymil=(20+50) 2=35. On s'aperçoit que le milieu est à gauche du bord droit, donc on repart en changeant les coordonnées gauches de la ligne, qui devient donc Pl'(275,35)-P2(400,50). On calcule à nouveau le milieu (337.42). Il est à droite du bord, donc on recommence en installant cette fois-ci les coordonnées droites de la ligne Pl'(275,35)-P2’(337,42). Ainsi de suite, on obtient les coordonnées suivantes :
Milieu Droite
(306. 38) (306,38)-(337.42)
(321. 40) (306,38)-(321.40)
(313. 39) (313,39)-(321.40)
(317. 40) (317.40)-(321.40)
(319. 40) (319.40)-(321.40)
(320. 40) (319,40)-(320.40)
Enfin on est parvenu à la droite finale, de coordonnées (150.20)-(320,40). Dans la réalité, il faut effectuer cette opération pour chaque bord de I’ecran.
Pour connaître les intersections, j’aurais pu aussi utiliser les calculs maniant le coefficient directeur, c'est-à-dire (y2-yl) (x2-xl). Il y a dans cette technique une formule pour l'intersection avec chaque bord. Par exemple, pour le bord droit :
y_inter=y 1 +( x_max-x 1 )*(y2-y 1 ) (x2-x I )
Cette formule utilise une multiplication et une division, sans se préoccuper de la taille de la droite ; elle est donc rapidement plus efficace que la dichotomie. Vous vous demandez peut-être pourquoi je ne l’utilise pas, si elle est si bien que cela. Ce choix est motivé par les deux défauts de cette technique : vous vous doutez que le coefficient directeur ne sera pas un nombre entier, et comme le 68000 ne permet que la division de nombres entiers, nous serons obligés de simuler une virgule en multipliant par un nombre suffisament grand avant les calculs, puis de diviser le résultat par ce même nombre pour obtenir le véritable résultat. Ceci diminue l'erreur mais ne l'efface pas, ce qui a pour conséquence de donner une impression de tremblement à la droite en mouvement. De plus réserver, des bits à la partie décimale en enlève à la partie entière. Voici un exemple où ceci poserait un problème : soit n=6. La partie entière est sur (16-n)=10 bits. Si celle-ci est supérieure à 2 puissance 10. Le résultat ne sera pas du tout celui attendu, donc il faut faire un test pour détecter ce cas. Ainsi qu'une nouvelle routine (cf. Dichotomie) pour calculer l'intersection dans ce cas. L'aspect de tremblement et un source plus complexe et plus long m'ont inciter a choisir la dichotomie.
ASTUCES GENERALES
Vous avez probablement remarqué que je modifie les instructions de "coor_e_to_coor_p" avec la routine "compute_sin_cos". Cette technique se nomme "l'assembleur automodifié" et permet de gagner du temps machine et quelques octets (plus précisément. 4 cycles et 2 octets à chaque utilisation des valeurs en question). Donc, on obtient daas ce cas précis un gain de 4*6 cycles par point calculé.
Autre astuce, l’effacement de l'écran se fait avec le blitter. Qui est quand même l'outil le plus rapide pour cette opération. Mais la priorité blitter ne fonctionnant pas dans ce cas. On est forcé de l'attendre, perdant ainsi beaucoup de cycles inutilement. Au lieu de patienter, on efface une partie de l'écran avec le 68000. Réduisant ainsi la taille du bloc blitter. Et donc le temps nécessaire.
FORMULES MATHEMATIQUES
La 3D suppose des calculs relativement complexes, que je ne ferai que citer pour ne pas ennuyer la galerie. Ils sont programmés dans "coor_e_to_coor_p".
- rotation autour de l’axe (OX) :
Y'= Y * cos(ax)- Z * sin(ax)
Z = Y * sin(ax)+ Z * cos(ax)
- rotation autour de l'axe (OY) :
X'= X * cos(ay)- Z * sin(ay)
Z'= X * sin(ay)+ Z * cos(ay)
- rotation autour de l'axe (OZ) :
X'= X * cos(az)- Y * sin(az)
Y'= X * sin(az)+ Y * cos(az)
Pour finir, je voudrais signaler que ce source n'as pas pour but de faire la 3D la plus rapide du monde, mais plutôt d'initier les débutants dans ce domaine. Vous aurez droit le mois prochain à un source de 3D faces cachées.
* *» Inclusion du fichier Hardware Custon. I
* ** qui se trouve sur le Disk 2 de Devpac
include 'include:hardware eustan.i'
openlibrary= -552
forbid = -132
permit = -138
key = SbfecOl
custera = $ df fOOQ
execbase = 4
plane_x = 352
plane_y = 285
line_width = plane_x 8
wait_blt: macro
btst 14,dmaconr(a5) * 2 appels a dmaconr canne le
loop_wait_blt@: * demande 'hardware manual'
btst 14,dmaconr(a5)
bne. S loop_wait_blt@
début: move.l (execbase) .w,a6 * Initialise a5 et a6
lea custcm,a5 *
jsr forbid(a6) * stoppe le multitâche
move.w $ 03e0,dmacon(a5) * dma off
move.l clist,copllc(a5) * lance ma propre
clr.w copjmpl(a5) * copper list
move.w $ 87c0,dmacon(a5) * dma ccçper & bitplan on
vsync: move.l vposr(a5),d0 *
and.l $ lff00,d0 * > attend que le balayage
cmp.l $ 00f00,d0 * > soit en haut de 1'écran
bne.s vsync *
wait bit
* efface l'objet
move.l
bpl log adr(pc),bltdpt(a5)
* pointe sur 1'écran
clr.w
bltdmod(a5)
move.w
$ 100,bltconO(a5)
* remplir avec des zéros
clr.w
bltccnl(a5)
move.w
204*64+line_width 2,bltsize(a5)
move.l
sp,save_sp
movem. 1 empty__buf fer (pc), d0-a6
move.l
bpl_log_adr(pc),a7
add.l
plane_y*line_width,a7
move.w
6,clr 68000 counter
clr 68000:rept
10
*
movem.1 d0-a6, - (sp)
* > efface 600 octets
endr
*
subq.w
1,clr_68000_counter
bne.s
Clr_68000
lea eus tan, a5
move.l
save_sp(pc),sp
bsr carpute_sin_cos
bsr coor_e_to_coor_p
bsr move_obj
move.l
coor_p(pc),al
* dessine les lignes
lea tab_line(pc),a2
move.w
(a2)+,count_1ine
loop_draw_obj:
move.w
(a2)+,d0
movem.w
(al,d0.w),d0-dl
move.w
(a2)+,d2
movem.vj
(al,d2.w),d2-d3
bsr clip_line
subq.w
l,count_line
bne.s
locp_draw_obj
move.l
coor_p(pc),a0
move.l
coor_p_buf(pc),coor_p
move.l
a0,coor_p_buf
move.l
plane_adr(pc),aO
*
move.l
bpl_log_adr(pc),plane_adr
* >inverse les 2 écrans
move.l
aO,bpl_log_adr
*
lea clist.aO
*
move.w
plane_adr(pc),2(aO)
* >change la ccpper list
move.w
plane_adr+2(pc),6(aO)
*
btst
6,SbfeOOl
* > en quitte si en appuie sur
beq init_end
* le Vnvm gant-bp de la souris
bra vsync
count_line: ds.
W 1
save_sp: ds.
1 1
clr_68000_counter: ds.l 1
empty_Jbuffer :
dcb.l 15,0
move_obj:
move.b
key,d0
not dO
ror.b
l,d0
and.w
$ ff,d0
cmp.w
$ 3d,d0
bne. S
not_key_7
addq.w
1,inc_ang_a+2
not_key_7:
cnp.w
$ ld,d0
bne. S
not_key_l
subq.w
1,inc_ang_a+2
not_key_l:
cnp.w
$ 2d,d0
bne. S
not_key_4
clr.w
inc_ang_a+2
not_key_4:
cmp.w
S3e,dO
bne. S
not_key_8
addq.w
1,inc_ang_b+2
not_key_8:
cnp.w
$ le,d0
bne. S
not_key_2
subq.w
1,inc_ang_b+2
not_key_2 :
cnp.w
$ 2e,d0
bne. S
not_key_5
clr.w
inc_ang_b+2
not_key_5:
cnp.w
$ 3f,d0
bne.s
not_key_9
addq.w
1,inc_ang_c+2
not_key_9:
cmp.w
$ lf,d0
bne. S
not_key_3
subq.w
1,inc_ang_c+2
not_key_3:
S2f.dO
tue. s
not_key_6
clr.w
inc_ang_c+2
not_key_6:
cmp.w
$ f,d0
bue.s
not_key_0
add.w
10,coor_z_val+2
not_key_0:
cnp.w
$ 3c,d0
bne.s
not_key_point
sub.w
10,coor_z_val+2
not_key_point:
rts
coor_e_to_coor_p:
lea
coor_e(pc),a0
move.l
coor_p(pc),al
move.w
(a0)+,d7
loop_coor_e_to_coor_p:
movem.w
(a0)+,d0-d2 ; dO d2 = coor e
cos_c_val:
move.w
0,d4
sin_c_val:
move.w
0,d5
nove.w
d0,d3
move.w
dl,d6
muls
d5,d0
suis
d4,d6
sub.l
d6,d0
add.l
d0,d0
swap
dO
suis
d4,d3
nuls
d5,dl
add.l
d3,dl
add.l
dl. dl
swap
dl
cos_b_val:
move.w
0,d4
sin_b_val:
move.w
0,d5
move.w
d0,d3
move.w
d2,d6
nuls
d5,d0
nuls
d4,d6
sub.l
d6,d0
add.l
d0,d0
swap
dO
nuls
d3,d4
nuls
d5,d2
add.l
d4,d2
add.l
d2,d2
swap
d2
COS_a_val:
move.w
0,d4
sin_a_val:
move.w
0,d5
move.w
dl,d3
move.w
d2,d6
nuls
d5,dl
muls
d4,d6
sub.l
d6,dl
add.l
dl. dl
swap
dl
nuls
d3,d4
nuls
d5,d2
add.l
d4,d2
add.l
d2,d2
swap
d2
coorzval:
add.w
$ 600,d2
ext.l
dO
ext.l
dl
moveq
9,d3
asl.l
d3,d0
asl.l
d3,dl
tst.w
d2
beq.s
no_div_by zéro
divs
d2,d0
divs
d2,dl
no_div_by_ zéro:
add.w
plane_x 2,dO
add.w
plane_y 2,dl
move.w
dO,(al)+ * > d0-dl= coor p
move.w
dl, (al)+ *
dbra
d7,locp_coor_e_to_coor_p
rts
ccmpute_sin_cos:
inc_ang_a:
add.w
0,ang_a+2
inc_ang_b:
add.w
0,ang_b+2
inc_ang_c:
add.w
0,ang_c+2
lea
cos_tab(pc) ,a0
move.w
$ 100,d6
move.w
$ 3fe,d7
ang_c: move.w
0,d3
; d3= angle * 2
and. W
d7,d3
¦
move.w
(a0,d3.w) ,d4
; > d4 = cos(c)
add.w
d6,d3
;
and. W
d7,d3
; > d5 = sin(c)
move.w
(a0,d3.w) ,d5
;
move.w
d4,cos_c_val+2
; put cos in ram
move.w
d5,sin c val+2
; put sin in ram
ang_b: move.w
0,d3
; d3= angle *2
and.w
d7,d3
move.w
(a0,d3.w),d4
; > d4 = cos b
add.w
d6,d3
.
And.w
d7,d3
; > d5 = sin b
move.w
(a0,d3.w),d5
;
move.w
d4,cos_b_val+2
; put cos in ram
move.w
d5,sin b val+2
; put sin in ram
anga : move.w
0,d3
; 33= angle*2
and.w
d7,d3
move.w
(a0,d3.w) ,d4
; > d4= cos a
add.w
d6,d3
.
And.w
d7,d3
; > d5= sin a
move.w
(a0,d3.w) ,d5
;
move.w
d4,cos_a_val+2
; put cos in ram
move.w
d5,sin_a_val+2
; tut sin in ram
rts
inter_y move.w
d0,d4
*
add.w
d2,d4
* >calcule le milieu X
asr.w
l,d4
*
move.w
dl,d5
*
add.w
d3,d5
* >calcule le milieu Y
asr.w
l,d5
*
cmp.w
d6,d5
bue.s
inter_y_not found
rts
inter_y_not_found:
cnp.w
d6,d5
*
bit. S
middle inf_y
* if middle_y(d5) is greater
move.w
d4,d2
* > than d6
move.w
d5,d3
* then modify coord and locp
bra.s
inter_y
*
middle_inf_y:
move.w
d4,d0
* f middle_y(d5) is less
move.w
d5,dl
* than d6
bra.s
inter_y
* then modify coord and locp
inter_x move.w
d0,d4
*
add.w
d2,d4
* > Calcule le milieu X
asr.w
l,d4
*
move.w
dl,d5
*
add.w
d3,d5
* > Calcule le milieu Y
asr.w
l,d5
*
cmp.w
d6,d4
bue. S
inter_x_not_found
rts
inter_x_not_found:
cmp.w
d6,d4
*
bit. S
middle inf x
* if middle_x(d4) is greater
move.w
d4,d2
* > than d6
move.w
d5,d3
* then modify coord and locp
bra.s
inter_x
*
middle_inf _x :
move.w
d4,d0
* f middle_x(d4) is less
move.w
d5,dl
* than d6
bra.s
inter x
* then modify coord and locp
xl : ds.w
2
x2 : ds.w
2
x_min =
0
xmax =
plane x-1
y_min -
0
y_max =
plane_y-l
clip_line:
cmp.w
d2,d0

ble.s
xl less x2
*
exg
d0,d2
* >after that dO = d2
exg
dl,d3
*
xl_less_x2:
*
movem.w
d0-d3,xl
* save coor in buffer
cnp.w
x_max,d2
*
ble.s
no_ inter_x_max
* > ail line is at left of x max
cnp.w
x_max,d0
*
bgt
line_unvisible
* > ail line is at rigbt of x_max
move.w
x_max,d6
*
bsr
inter_x
* ccnpute intersectoin with x max
movem.w
d4-d5,x2
* adn modify the coor
movem.w
xl(pc),d0-d3
*
no_inter_x_max :
cnp.w
x_min,d0
*
bge.s
no_inter_x_min
* > ail line is at right of x min
cnp.w
x_min,d2
*
ble line_unvisible * > ail line is at left of x_min move.w ibc_min,d6 *
bsi inter_x * cccpute intersection with x_min movem.w d4-d5,xl * adn modify the coor
movem.w xl(pc) ,d0-d3 *
no_inter_x_min:
cmp.w d3,dl *
ble. S yl_less_y2 *
exg d0,d2 * >after that dl = d3
exg dl,d3 *
yl_less_y2: *
movem.w d0-d3,xl * save coor in fcuffer
cmp.w y_max,d3 *
ble.s no_inter_y_max * > ail line is at left of y_max cmp.w y_max,dl *
bgt line_unvisible * > ail line is at rigbt of y_max move .w y_max, d6 *
bsr inter_y * ccnpute intersectoin with y_max
movem.w d4-d5,x2 * adn modify the coor
movem.w xl(pc) ,d0-d3 *
no_inter_y_max:
esnp.w y_min, dl *
bge.s no_inter_y_min * > ail line is at right of y_min cmp.w y_min,d3 *
ble line_unvisible * > ail line is at left of y_min move.w y_min,d6 *
bsr inter_y * cccpute intersection with y_min
movem.w d4-d5,xl * adn modify the coor
movem.w xl(pc),d0-d3 * no_inter_y_min :
draw_line: * D0,D1 : X,Y INITALE D2,D3 : X,Y FINAL
* d0-d6 a0 are destroyed ! Voir Hardware Manuel pour + de détails
line_visible:
sub.w
d0,d2
bmi.s
xneg
sub.w
dl,d3
hmi . S
yneg
cmp.w
d3,d2
txni.s
ygtx
moveq
%0011001,d5
bra.s
lineagain
ygtx: exg d2,d3
moveq
%0000101,d5
bra.s
lineagain
yneg : neg. W
d3
cnp. W
d3,d2
bmi. S
ynygtx
moveq
%0010001,d5
bra.s
lineagain
ynygtx: exg d2,
d3
moveq
%0000001,d5
bra.s
lineagain
xneg: neg.w
d2
sub.w
dl,d3
kmi.s
xyneg
cnp.w
d3,d2
kmi.s
xnygtx
moveq
%0011101,d5
bra.s
lineagain
xnygtx: exg d2,
d3
moveq
%0001101,d5
bra.s
lineagain
xyneg: neg.w
d3
cnp.w
d3,d2
kmi.s
xynygtx
moveq
%0010101,d5
bra.s
lineagain
xynygtx : exg d2,
d3
moveq
%0001001,d5
lineagain:
move.l
kpl_log_adr(pc),aO
mulu
line_width,dl
ror.l
4,d0
add.w
dO.dO
add.l
dl. aO
add.w
d0,a0
swap
dO
or.w
$ bfa,dO
lsl.w
2,d3
add.w
d2,d2
move.w
d2,dl
lsl.w
5,dl
add.w
$ 42,dl
waitjblt
move.w
d3,bltkmod(a5)
sub.w
d2,d3
move.w
d3,bltapt+2(a5)
bpl.s
lineover
or.w
$ 40,d5
1 ineerver : sub. W
d2,d3
move.w
33,bltamod(a5)
move.w
dO,bltconO(a5)
move.w
d5,bltconl(a5)
move.w
-line_width,bltcmod(a5)
move.w -line_width,bltdmod(a5)
move.w $ 8000,bltadat(a5)
moveq -l,d5 * va plus vite que
move.l d5,bltafwm(a5) * > 'move.l -l,bltafwm(a5)'
move.l a0,bltcpt(a5)
move.l a0,bltdpt(a5)
move.w dl,bltsize(a5)
1 ine_urrvisible : rts
init end
init_end:move.l (execbase) .w,a6
lea gmame(pc) ,al *
moveq 0,d0 *
jsr cpenlibrary(a6) * >réactivation et lancement
move.l d0,a4 * >de l'ancienne cqpper list
move.l 38(a4),copllc(a5) *
clr.w copjnpl(a5) *
move.w $ 83e0,dmacon(a5) * dma on
jsr permit(a6) * multitâche autorise
moveq 0,d0 ; flag d'erreur desactive
rts
gmame: dc.b "graphies.library”,0,0 plane_adr: de. 1 ecranl
bpl_log_adr: dc.l ecran2
coor_p: dc.l coor_pl
coor_p_buf : de. 1 coor_p2
cos_tab: include 'cos_tab.s'
c = 100
coor e : de .w 7 * = nombre de points -1
dc. w c,c,c, c,-c,c, -c,-c,c, -c,c,c de .w c,c,-c, c,-c,-c, -c,-c,-c, -c,c,
tab_line:
dc. w 12 * = nombre de lignes
dc. w 0,4, 4,8, 8,12, 12,0
dc. w 16,20, 20,24, 24,28, 28,16
dc. w 0,16, 4,20, 8,24, 12,28
coor_pl ds. 1 8 * = nombre de points
coor_p2 ds.l 8 * = nombre de points
sect ion copper_l ist, data_c
dc. w fcplpt, 0, bplpt+2,0, fcplconO, $ 1200, bplconl, 0,fcplcon2,0
dc. w fcpllmod, 0,bpl2mod, 0,diwstrt, $ lb71,diwstop, $ 39dl
dc. w ddfstrt,$ 30,ddfstop,$ d8,-l,-2
ecranl ds. 1 line_width*plane_y 4
ecran2 ds. 1 line_width*plane_y 4
LISTING 2
Programme GfABasic pour créer la table des cosinus
OPEN "o", l,"ram:cos_tab.s"
nbval=512 ! Nombre de valeurs dans la table
FOR i&=0 TO (5*nbval 4)-8 STEP 8 PRINT 1,CHR$ (9);"dc.w";CHR$ (9);
FOR j&=i& TO i&+6
PRINT 1,"$ ";HEX$ (®s(j&),4);",";
NEXT j&
PRINT 1,"$ ";HEX$ (0s(j&),4)
NEXT i&
CLOSE 1 EDIT
FUNCTICN S (x) val=SIN(x nbval*2*PI)
IF val=l
val=0.99999999999 ENDIF
RETORN INT(val*32768)
ENDFONC
MINITEL : TAPER 3615 CODE "ANT"
UTILITAIRE
Si vous programmez beaucoup, et c’est certainement le cas puisque vous lisez l’ANT, vous en avez peut-être eu assez, à un certain moment, d’être obligé de compter les pixels sur votre écran et de définir à chaque fois toute une structure pour ouvrir une simple fenêtre sous Intuition. Et comme tout le monde ne possède pas PowerWindows à la maison, je vous propose ce mois-ci un petit utilitaire destiné à vous faciliter la tâche._
B
LES FENETRES F
est fait très simplement en donnant une structure de bord avec une couleur différente dans le champ SelectRender de la structure du gadget. Pour assurer le maintient de la nouvelle couleur, il faut sélectionner le flag TOGGLESELECT dans le champs de flags des structures Gadget. On obtient alors un effet de bascule.
Vous verrez aussi un bon exemple d'utilisation et de rafraîchissement d'un aadaet de chaîne.
LA FONCTION PutCoord
Dans cette fonction, il faut transformer les dimensions de la fenêtre de réglage en chaîne de caractères. La librarie standard du SAS ne comporte pas de fonction prévue à cet effet, c'est-à-dire une fonction capable de transformer un entier en chaîne, bien qu'il existe la fonction inverse. De plus les dimensions de la fenêtre ne sont pas données en entiers mais en "shorts".
En fait, il existe la fonction gctv() qui sait convertir un flottant en chaîne de caractères. C'est pour cela que les "shorts" des dimensions de fenêtres sont d'abord castés en "double".
Les plus perspicaces d'entre vous n'ont pas été sans remarquer que le cas du zéro est traité séparément.
En effet, la fonction gcvt() est tout-à-fait satisfaisante tant que le "short" casté en "double" n'est pas nul. Le résultat est exactement le même qui si l'on avait une fonction itoa. Par contre, pour une valeur nulle, la fonction renvoie la chaîne "0.” c’est-à-dire qu'elle ajoute arbitrarement une virgule (enfin, un point). Je me demande bien pourquoi, mais il faut faire avec.
Ce programme peut être indifférement appelé depuis le CLI ou depuis le YvorkBench. Dans un premier temps, le programme ouvre une fenêtre munie d'un gadget de chaîne dans lequel vous devez tapez un nom de fichier valide. Si vous ne précisez pas le chemin, c'est dans le répertoire courant que sera créé le fichier. Si vous donnez un nom de fichier incorrect, le programme refusera d’aller plus loin et vous redemandera un nom de fichier valide.
Le principal est dit sur ce programme qui ne comporte pas de difficultés particulières. Encore une fois, rien ne vous empêche de le modifier à votre convenance, et même d'étendre le procédé aux structures NewScreen et aux structures gadgets, pourquoi pas ?
Dès que cette condition est satisfaite, le programme vous demande, dans le même gadget de chaîne, de donner un nom à la structure NewWindow que vous êtes en train de créer. Bien entendu, ce nom peut être totalement différent du nom de fichier que vous avez donné précédemment.
Progranme: easywindcw.c
Fonction: Presnet la création rapide d'une structure NewWindow insérable dans un source C Remarque: Nécéssite le source data.c Ccnpilateur: SAS 5.10
Compilation: le -mOs -rl -cist -v -y easywindow.c Auteur: F MAZUE pour ANT le 10 02 91
Après cela, vous verrez s'ouvrir sur votre écran une fenêtre ayant pour titre: "fenêtre de réglage". Il vous suffit de déplacer, dimensionner. Et positionner cette fenêtre comme bon vous semble. Pour valider cette position, cliquez le gadget de fermeture de la fenêtre de réglage. Les caractéristiques de la fenêtre au moment de la fermeture seront enregistrées dans la structure NewWindow et écrites dans le fichier.
Linkage: FRCW LIB:c.o data.o easywindow.o TO easywindow LI3 LIB:lcm.lib LIB:lC.lib LIB:amiga.lib
Ensuite s'ouvrira une fenêtre munie d une ribambelle de gadgets booléens, pour la sélection des flags IDCMP. Pour sélectionner un flasz. Il suffit de
SMALLCODE
SMAI.I.DATA
cliquer dessus. Si vous changez d'avis dans la sélection d'un flag. Il suffit de '' define _main = tinymain
cliquer une deuxième fois sur son gadget. Quand tout vous convient, cliquez sur le gadget OK pour valider.
include exec types.h>
include exec execbase.h> include exec memory.h>
include intuition intuition.h> include intuition screens.h> include string.h>
include stdio.h>
Même chose pour les flags de la fenêtre : une ribambelle de gadgets booléens apparaît : gadget de fermeture, barre de déplacement, etc... La sélection et la validation se font de la même façon que précédemment. Enfin et pour terminer, vous devrez donner, dans le gadget de chaîne de la toute première fenêtre ouverte, une chaîne correspondant au titre de la fenêtre, et c'est tout.
Comme vous ne manquerez pas d'aller voir le fichier résultat des opérations, vous constaterez que la structure est valable pour une fenêtre s'ouvrant dans l'écran du WorkBench. Si cela ne vous convient pas. Vous pourrez modifier "à la main”, mais rien ne vous empêche de faire mieux, c'est-à-dire compléter ce programme à votre guise. Je ne l'ai pas fait ici car le listing est déjà important et je ne veux pas monopoliser toute la place. Les modifications et compléments sont faciles à apporter, car le programme a été écrit dans cette intention (NDMax: c’est pas comme le SuperShell... hé. Hé. Hé).
Si vous relancez une deuxième fois EasyWindow en donnant le même nom de fichier, la première structure NewWindow créée ne sera pas écrasée mais simplement la deuxième lui fera suite. Vous pouvez également modifier le programme en ajoutant une boucle de façon à avoir la possibilité de créer plusieurs structures NewWindow d’un seul coup. Après tout, cela n'est qu'une affaire de convenance personnelle.
* Sur Aztec: include functions.h>
ifdef LATTICE
include proto exec.h>
Sinclude proto graphics.h>
Sinclude proto intuition.h>
endif
* EXTERNES
*:
extern ÜBYTE Buffer[80]; extern char *text[]; extern char *Flags[]; extern char *IDCMP[];
extern struct NewWindow NewFlagsWindow; extern struct NewWindow NewReglage; extern struct Gadget MyStringGadget; extern struct Gadget OKGadget; extern struct Gadget FlagsGadgets[]; extern struct Gadget HXMPGadgets[j; extern struct NewWindow NewTextWindow; extern USHORT Témoin[22];
POUR LES PROGRAMMEURS
GLOBALES
Je pense que ce programme est un exemple intéressant d'utilisation des gadgets. Vous y verrez comment chaîner des gadgets booléens et comment trouver lequel est sélectionné. Dans les fenêtres de sélection des flags, vous verrez que le bord des gadgets change de couleurs lors de la sélection. Ceci
struct intuitionBase *IntuitionBase = NüLL; struct GfxBase ‘GfxBase = NOLL; struct Window *TextWindow, *Reglage,
«FlagsWindow, *!DCMPWindow;
ACILES
FILE *fp; * pour fichier tamponné *
* Déclarations des fonctions *
VOID Clean_Exit(void);
VOID Chaîne(char *);
VOID PutCoord(SHORT, SHORT);
VOID ResetTemoin(void);
VOID PutFlags(char «flags [], int) ; int handlelDCMP ( struct Windcw * ) ;
* LET'S GO ! *
VOID maint)

BOOL file_done; int done =0;
if (!(GfxBase=(struct GfxBase *) CpenLibrary )
("graphies.library",0)))
Clean_Exit();
if (!(IntuitionBase = struct IntuitionBase*
OpenLibrary( "intuition, library",0) ) )
Clean_Exit();
if ( (TextWindow = (struct Window *)QpenWindcw (SNewTextWindcw) ) = NOLL)
Clean_Exit();
ltove( TextWindow->RPort,10,8);
Text(TextWindow->RPort,text[0],
strlen(text[0]));
* Attente d'un nom de fichier correct *
do

ActivateGadget(&MyStringGadget,TextWindow, 0); Waitt IL « TextWindow->UserPort->np_SigBit); fp = fopentBuffer,"a"); if(fp) file_done = TRDE;
}while(!file_done);
strcpy(Buffer,
Chainet"struct NewWindow ");
* Rafraîchissement du gadget de chaîne *
* puis attente d'un Nctn pour la structure*
* window *
Move ( TextWindow- >RPort, 10,8 ) ;
Text (TéxtWindow->RPart, text [1], strlen(text[l] ) ) ; RefreshGadgets ( SmyStringGadget, TextWindcw.MJLL) ; ActivateGadget (&MyStringGadget, TextWindcw, tWIL ) ; Waitt IL « TextWindow->üserPort->np_SigBit);
Chaine(Buffer);
Chainet" = ");
* Mise en place de la fenêtre de *
* réglage puis attente de la fermeture *

if ( (Reglage = (struct Window *)cç>enWindcw
(&NewReglage)) == NOLL)
Clean_Bxit();
Move(Reglage->RPort,65,50); Text(Reglage->RPort,text[3]«strienttext[3])); Move(Reglage->RPort,120,70);
Text(Reglage->RPort,text[4]«strienttext[4])); Waitt IL « Reglage->UserPort->mp_SigBit);
PutCoord(Reglage->LeftEdge, Reglage->TopEdge); PutCoord(Reglage->width, Reglage->Height);
Chaine("1,0,"); * couleurs par défaut *
CloseWindcw ( Reglage ) ;
* Mise en place de la chaîne de gadgets bool *
.NextGadget = SIDCMPGadgets[21);
;.Title= "Selecticsi des FlagsIEOÎP" ; if t(IDCMPWindow=( struct Windcw * ) CpenWindow
(SUewFlagsWindOf) ) == NOLL)
Clean_Exit ( ) ;
ResetTenoint ) ; vdiilet idone)
Waitt IL IDCMPWiry3cw->UserPort->rnp_SigBit) ; done = handlelDCMP ( iDCMPWindow) ;
PutFlags(IDCMP,22) ;
* Deuxième série de gadgets booléens *
OKGadget.NextGadget = &FlagsGadgets[13]; NewFlagsWindow.Title="Selection des Flags";
if ( (FlagsWindcw=(struct Windcw *)Oper*findcw
(ScNewFlagswindcw) ) = NOLL)
Clean_Exit();
CloseWindcw ( IDCMPWindcw ) ;
IDCMPWindow = 0; done=0;
ResetTemoin();
vdiilet idone)

Waitt IL « FlagsWindow->UserPort->np_SigBit); done = handlelDCMP(FlagsWindcw);
PutFlags(Flags,14);
CloseWindow(FlagsWindcw);
FlagsWindw = 0;
Chaine("NOLL,NOLL,");
);
strcpy(Buffer, Chaine(""");
***********»************»*****«***********?
* Dernier rafraîchissement du gadget de * * chaîne pour saisie du titre de la fenêtr*
y***********************»***********»*****»*
Move ( TextWindw->RPort, 10,8 ) ; Text(TextWindcw->RPort,text[2], striai (text [2]) ); Ref reshGadgets ( &MyStringGadget, TextWindcw,t*JLL) ; Activatefedget (SMyStrir Gadget, TextWindcw, NOLL) ; Waitt IL « TextWindow->UserPort->np_SigBit);
Chaine(Buffer);
Chainet"",");
Chainet"NOLL,NOLL,10,10,640,256,
Clean_Exit() ;
Fonction pour rendre la main proprement
VOID Clean_Exit()
fclose(fp);
if ( IDCMPWindow) CloseWindwt IDCMPWindow) ; if(FlagsWindow) CloseWindow(FlagsWindow); if (TextWindow) CloseWindow (TextWindow) ; if (GfxBase) CloseLibrary(GfxBase); if (IntuitiœBase) CloseLibrary (IntuitionBase); exit(0);
}
* cette fonction écrit la chaîne de ce *
* caractère reçu en paramètre dans le *
* fichier dont le pointeur est une *
* variable globale *
***************************************** VOID Chaine(char *chaine)

fprintf(fp,chaine);
* Cette fœcticn transforme les coord, de la* * fenêtre en chaine de caractères pris les * * envoie dans le fichier par de la fonction* * précédente *
VOID PutCoord(SHORT X, SHORT Y)

char- x [4] ; * 4 parce que 0 de fin de chaîne * char y[4] ;
if (X==0) strcpy(x,"0"); else gcvt((double)X,3,x);
if (Y==0) strcpy(y,"0"); else gcvt((double)Y,3,y);
Chainet","); Chaine(y); Chaine(",");
•Cette fcncticn rafraîchit le tableau témoin * ?pour la sélection des gadgets booléens *
VOID ResetTemoin(void)

int i = 0;
for(i=0;i 22;i++) Temoin[i]=0;
}
*****?*************************************
•Cette fonction examine les IntuiMessages,* •renvoie 1 sur le gadget booléen OK est *
•sélectionné, sinon remplit le tableau *
«témoin sur le gadget sélectionné *
********»**»«******•******»*••**•***••••*•* int handlelDCMP (struct Windcw *win)

int flag=0;
ULONG class;
struct Gadget *iaddress;
USHORT ID;
struct IntuiMessage «message = NOLL;
while(message=(struct IntuiMessage *)
GetMsg(win->UserPort))

class = message->Class;
iaddress = (struct Gadget *)message->IAddress;
ID=iaddress->GadgetID;
switch(class)

case GADGETOP:

switch(ID)

case 50: flag = 1; break;
default:
if(Témoin[ID]) Témoin [ID]=0; else
Témoin [ID]=1; break;
default: break;
retum(flag) ;
•Cette fonction examine le tableau témoin * •et envoie les chaînes de caractères cor- * •-respondant aux flags sélectionnés le * •fichier par appel de la fonction Chainet)* **********»****»************»*»************ VOID PutFlags(char *flags[], int limite)

int i=0;
int cccpteur=0;
for(i=0;i limite;i++)

if(Temoin[i]) ccnpteur++;
}
if ( îccnpteur)

Chaine("NOLL,"); returo;
for(i=0;i limite;i++)
(
if(Temoin[i])
(
Chaine(flags[i]); if ( compteur)

Chaine("I");
else

Chaine(",");
}
}
}
par Frédéric Mazué
Fonction: à carpiler et linker avec easywindcw.c Ccnpilateur: SAS 5.10
C
1,0, JAM1, 1,0, JAM1, 1,0,JAM1, 1,0,JAM1, 1,0,OAM1, 1,0,JAM1, 1,0, JAKL, 1,0, JAM1, 1,0, JAM1, 1, 0, JAM1, 1,0, JAM1, 1,0,JAM1, 1,0,JAM1, 1,0, JAM1, 1,0, JAM1, 1,0, JAM1, 1,0,0AM1, 1, 0, JAM1, 1, 0,JXM1, 1,0, JAM1,
1,0,JAM1, 1,0, JAKL,
5. 5,NÜLL 5, 5,NÜLL
5. 5,NÜLL
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL, 5, 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
5. 5,NÜLL,
Carpilation: le -mOs -rl -cist -v -y data.c
include exec types.h>
include intuition intuition.h>
char *text[] =

"tfcm de fichier à créér ?",
"Nom de la structure NewWindow
"Pcxir terminer donnez un titre à votre fenêtre"
"Reglez la position et les dimensions",
"Fermez pour valider"
};
"MXJSEBÜTTONS ", NÜLL}, "M0üSa*>VE", NÜLL}, "DELTAMOVE”,NÜLL}, "GADGETDCMN", NÜLL}, "GADGETOP",NÜLL}, "CLOSEWINDCW",NÜLL}, "MENOPICK",NüLL}, "MENÜVERIFY",NÜLL}, "REQSET”,NÜLL}, "REQCLEAR", NÜLL}, "REQVERIFY",NÜLL}, "NEWSIZE",NÜLL}, "REFRESHWINDOW",NÜLL}, "SIZEVERIFY",NÜLL}, "ACTIVEWINDCW", NÜLL},
" INACnVEWINrCW", NÜLL}, "VANILLAKEY", NÜLL}, "RAWKEY",NÜLL}, "NEWPREFS",NÜLL},
i",NÜLL}, ,NOLL}, 3NIÜITICKS ", NCLL},
char *Flags[] =

"WINDCWSIZIN3", "WINDOWDEPTO" "WINDCW2LOSE", "WINDOWraAG", "SIMPLE_REFRESH", "SMA _
.BITMAP", "BACKDROP"
* Tableaux de structures pour gadgets
define PARTIE_CCMDNE,
Ll(x) GADOKXMPIGADŒIMAGE, RELVERIFY,
"ACTIVATE" "RMBTRAP",
} ;
(APTR)&FlagsBord,(APTR)&FlagsBordl, SflagsText[x],
NüLL,NÜLL,x,NÜLL
char

struct Gadget FlagsGadgets[]
NÜLL,
&FlagsGadgets[0]
&FlagsGadgets[1]
&FlagsGadgets[2]
&FlagsGadgets[3]
&FlagsGadgets[4]
&FlagsGadgets[5] .
&FlagsGadgets[6] .
&FlagsGadgets[7] ,
&FlagsGadgets[8] ,
&FlagsGadgets[9] ,
SflagsGadgets[10],
&FlagsGadgets[ll],
"DELTAMOVE", "GADGEHJP", "MENOPICK",
"GADGETDCWN", "CLOSEWINDOW", "MENÜVERIFY",
5,
16,
120,
20,
130,
16,
120,
20,
255,
16,
120,
20,
380,
16,
120,
20,
5,
34,
120,
20,
130,
34,
120,
20,
255,
34,
120,
20,
380,
34,
120,
20,
5,
52,
120,
20,
130,
52,
120,
20,
255,
52,
120,
20,
380,
52,
120,
20,
5,
70,
120,
20,
130,
70,
120,
20,
PARTIE, PARTIE_CCMONE_ PARTIE_CCMÜNE_ PARTIE_CCKDNE. PARTIECCKüNE.
1(0)
.1(1)
1(2)
.1(3)
.1(4)
.1(5)
1(6)
1(7)
1(8)
1(9)
1(10)
1(11)
1(12)
1(13)
"REQVERIFY", "REFRESHWINDOW", "ACTIVEWINDOW", "VANILLAKEY",
"SIZEVERIFY",
" DBCTIVEWINDCW" "RAWKEY",
PARTIE_CCMDNE_ PARTIE_CCMDNE_ PARTIE_CCMDNE_ PARTIE_CCMDNE PARTIE_CCWÜNE_ PARTIE_COttJNE_ PARTIE_CCMONE_ PARTIE
"DISKREM3VED", };
"IOTOmCKS"
*
* les 3 structures qui suivent sont * utilisées par tous les gadgets *
Sdefine PARTIE_CCMDNE_2(x)
GADC2KXKPI GADGHIMA S,
TOGGLESELECTIRELVERIFY,
BOOLGADGET,
(APTR)&FlagsBord,(APTR)&FlagsBordl, &IDCMPText[x],
NÜLL,NÜLL,x,NÜLL
SHORT FlagsCoord[]=

0,0,120,0,120,16,0,16,0,0
;
struct Border FlagsBord =

0,0,1,0,JAM1,5, FlagsCoord, NüLL };
struct Gadget IKMPGadgets [ ] =
NÜLL,
5,
16,
120,
20,
&HXMPGadgets[0] ,
130,
16,
120,
20,
SIDCMPGadgets[1] ,
255,
16,
120,
20,
&IDCMPGadgets[2] ,
380,
16,
120,
20,
&DXMPGadgets [3] ,
5,
34,
120,
20,
&IDCMPGadgets[4] ,
130,
34,
120,
20,
SUXMPGadgets [ 5 ] ,
255,
34,
120,
20,
&IDCMPGadgets[6] ,
380,
34,
120,
20,
ScIDCMPGadgets [7] ,
5,
52,
120,
2C,
SIDCMPGadgets[8] ,
130,
52,
120,
20,
SIDCMPGadgets[9] ,
255,
52,
120,
20,
&HXMPGadgets [10],
380,
52,
120,
20,
&IDCMPGadgets[11],
5,
70,
120,
20,
&3DCMPGadgets[12],
130,
70,
120,
20,
&IDCMPGadgets[13],
255,
70,
120,
20,
&HXMPGadgets [ 14 ],
380,
70,
120,
20,
&IDCMPGadgets[15],
5,
88,
120,
20,
ScIDCMPGadgets [16],
130,
88,
120,
20,
ScIDCMPGadgets [17],
255,
88,
120,
20,
&lDCMPGaâgets[18],
380,
88,
120,
20,
SIDCMPGadgets[19],
5,
106,
120,
20,
siDCMPGadgets[20],
130,
106,
120,
20,
PARTIE CCMONE
PARTIE_COMONE PARTIE_CŒNE. PARTIE_COMONE
PARTIE.
PARTIE.
PARTIE.
PARTIE.
Partie!
PARTIE.
PARTIE.
PARTIE.
PARTIE.
PARTIE.
PARTIE.
PARTIE.
PARTIE.
PARTIE.
PARTIE
.2(0) .2(1) .2(2) .2(3) .2(4) .2(5) .2(6) .2(7) .2(8) .2(9) .2(10) .2(11) 2(12) 2(13) 2(14) .2(15) 2(16) 2(17) 2(18) .2(19) 2(20) .2(21) }
struct Border FlagsBordl =

0,0,3,0,JAM1,5,FlagsCoord,NüLL };
COMUNE.
CCMONE
Tableaux de structures IntuiText
struct IntuiText FlagsText[] =

1,0,JAM1,5,5,NÜLL,"WINDOWSIZING",NÜLL), 1,0, JAM1,5,5,NÜLL,"WINDOWDEPTH",NÜLL}, 1,0, JAM1,5,5,N0LL, "VJINDOWCLOSS",NÜLL},
1,0, JAM1, 5, 5,NÜLL, "WINDOWDRAG" ,NÜLL},
1,0,JAM1,5,5,NÜLL,"SIMPLE_REFRESH",NÜLL}, 1,0,JAM1,5,5,NÜLL,1 1,0, JAM1,5,5,NÜLL,1 1,0,JAM1,5,5,NÜLL, '
1,0, JAM1, 5,5,NÜLL, '
1,0,0AM1,5,5,NÜLL, '
1,0,JAM1,5,5,NÜLL,"ACTIVATE",NÜLL},
1,0,JAM1,5,5,NÜLL,"NOCAREREFRESH",NÜLL}, 1, 0, JAM1, 5, 5,NÜLL, "RMBTRAP",NÜLL},
1,0,JAM1,5,5,NÜLL,"GIMMEZEROZERO",NULL}
};
struct IntuiText IDCHPText[] =
CCMÜNE.
CCMONE
,NDLL>, BITMAP", NÜLL), NÜLL}, ".NÜLL), NÜLL),
Gadget booléen de validation
struct IntuiText OKText =
1,0,JAM1, 5,5,NÜLL,"OK",NULL };
SHC»T Okcoordonnees [ ] =
0,0,25,0,25,16,0,16,0,0 },-
struct
0,0,1,0,JAMl,5,OKcoort3onnees,NÜLL };
struct Border OKBordl =
0,Q,3,0,JftMl,5,0Kcoordonnees,NQLL };
Deuxième aspect de notre voyage au coeur d’Intuition, nous allons étudier ce mois-ci les gadgets, et plus particulièrement deux types de gadgets : les booléens et les gadgets de chaînes.
Struct Gadget OKGadget =

NULL,235,160,25,20,
GADGHCCMPIGADGHIMAGE, RELVERIFY, BOOLGADGET,
(APTO) &OKBord, (APTR)ScOKBordl, &OKText, NULL,NüLL,30,NULL };
* Définitiera de la fenetre à cwvrir * * pour le choix des flags *
struct NewWindcw NewFlagsWindcw =

70,54,510,202,
1,3,
GADGETOP, ACTIVATBIWINDCWEEPTO,
SOKGadget, NULL, "EASY WINDOW 1.0 F MAZUE", NULL,NULL,
200,50,200,50,
********••••*
la fenêtre à ouvrir
* Définition * pour 1 * de position
struct NewWindcw NewReglage =
100,50,440,100,1,3,
51WINDOWSIZINGI WINDCWDEPTH I ACTIVAIS 1WXNDOWXOSE,
NULL,NulL,
NULL, NULL,
10,10, 640,256,
* définition de la stringinfo * associée au gadget
UBYTE Buffer[80]="
struct Stringinfo MyStringlnfo =
Buffer,NULL,80,82,0,0,0,0,0,0,NULL,NULL,NULL };
SHORT string_coordcnnees [ ] =
-2,-2,480,-2,480,10,-2,10,-2,-2 };
struct Border StringBorder =
0,0,1,0,JAM1,5,string_coordormees,NULL };
Définition du gadget de chaîne
struct Gadget MyStringGadget =

NULL, 10,14,480,10,
GADGHCCMP, RELVERIFY, STRGADGET, (APTR)&StringBorder,NUIL,NULL,NULL, (APTO) &MyStringInfo, NULL, NULL };
* Définition de la fenêtre à cxivrir * pour les entrées de chaînes
struct NevMindow NewTextwindw =

70,12,510,42,1,3,
GADGETUP, ACTIVATE | GIMMHZEROZEROI WINDOfEePIU, &MyStringGadget,
NUIL, "EASY WINDOW 1.0 F MAZUE22",
NULL, NULL,
200,50, 200,50,
ÜSHORT Témoin[22];
Après l’article, un tantinet théorique, du mois dernier, et comme noas en savons désormais assez pour écrire une petite application, nous allons définir quelles seront les fonctionnalités du produit à réaliser et quels seront les moyens à mettre en oeuvre pour le faire. Le programme que nous allons réaliser est un simple convertisseur de formats de nombres. Trois formats seront traités : le décimal, l’héxadécimal et l’octal. Nous alloas donc créer trois gadgets booléeas qui nous permettront d'indiquer au programme sous quel format sera saisi le nombre à convertir. La saisie du nombre se fera quant à elle par l’intermédiaire d’un gadget de saisie de chaînes de caractères. La taille maximum du texte saisi doit correspondre à la taille maxi prise par un mot long en octal, soit 11 caractères. Une fois le texte saisi, celui-ci est converti dans les différents formats et affiché dans la fenêtre à coté des gadgets respectifs.
L'utilisation d'un tel programme est très simple. Au lancement, la fenêtre et les gadgets apparaissent, ainsi que le texte "Décimal" indiquant le mode de saisie par défaut du programme (il s'attend à recevoir un nombre décimal). Dès lors, deux choix s'offrent à l'utilisateur :
- saisir un nombre décimal pour qu'il soit traité :
- changer de format de saisie en cliquant sur "octal" ou "hexa".
Dans le cas où un nombre est saisi dans un format ne correspondant pas. Le programme n'interprète pas l’entrée et montre son mécontentement en faisant flasher l'écran.
REALISATION
La première chose qu'il nous faut faire, c'est ouvrir une fenêtre liée à un écran. L'écran que nous allons utiliser pour accrocher notre fenêtre est celui du Workbench. Par rapport à l'article du mois dernier, nous indiquerons donc dans le champ "NewWindow.Type" VVBENCHSCREEN à la place du CUSTOMSCREEN de la dernière fois.
Nous devons ensuite ensuite définir nos gadgets. Cette opération s'effectue en renseignant une liste chaînée de structures "Gadget". Voici le détail de la structure "Gadget” avec un rapide commentaire pour chaque champ.
Struct Gadget
struct Gadget ’NextGadget; * pointeur sur le suivant *
SHORT LeftEdge, TopEdge, Width, Height; * position et taille *
USHŒT Flags; * flags de gestion du gadget *
USHORT Activation; * la manière dont il sera activé *
USHORT GadgetType; * le type de gadget crée (Booléen ) *
APTR GadgetRender; * l'image cxi la bordure associée *
APTR SelectRender; * Image ou bordure sélectionée *
struct Intuitext *GadgetText; * texte associé au gadget *
LONG MutualExclude; * gestion de l'exclusion mutelle *
APTR Speciallnfo; * si gadget de chaînes ou proportionnel *
USHORT GadgetlD; * champ pour indiquer un numéro au gadget *
APTR User Data; * données quelconques. A vous de voir ! *
Le chaînage s’effectue en associant au gadget N, l’adresse du gadget N+l dans le champ "NextGadget". Lorsqu'il s'agit du dernier gadget de la liste, ce champ est mis à NULL. Une fois cette liste correctement renseignée, il ne reste plus qu'à la lier à la fenêtre. On indique l'adresse du premier gadget de la liste dans le champ "NewWindow.Gadget" et là, miracle, lorsque l'on demandera à Intuition d'ouvrir la fenêtre à l'aide de la fonction OpenWindowO, elle affichera automatiquement les gadgets.
Voyons un peu les caractéristiques du gadget Booléen. Un gadget est défini comme booléen (oui non) à partir du moment où l'on indique BOOLGADGET dans le champ GadgetType. Dans le cas qui nous intéresse, on veut que le gadget nous prévienne dès qu'il est activé et qu'il arrête d'être actif dès que l'on n’appuie plus dessus. On prendra soin de positionner pour ce faire le flag GADGIMMEDIATE dans le champ Activation de notre gadget.
Voilà notre gadget est prêt à l'emploi : dès que l'on cliquera dessus. Intuition nous enverra un message de classe GADGETDOWN (message->Class = GADGETDOWN) nous indiquant qu'un des gadgets de la liste a été sélectionné. Que faut-il faire maintenant ? Savoir quel gadget a été sélectionné bien sûr !
INSPECTION DES GADGETS
Nous avons plusieurs méthodes pour arriver à ce résultat :
- la première consiste, lorsque l’on a reçu le message GADGETDOWN d'intuition, à balayer la liste des gadgets et à vérifier quel gadget possède le flag SELECTED. Par exemple
if (gadgetl.Flags & SELECTED)
* le gadget1 est sélectionné *
SHORT MaxChars; * Nombre maxi de caractères *
SHORT DispPos; * Position dans le buffer du 1er car. Affiché * SHORT OndoPos; * Position dans le buffer UNDO *
SHORT NumChars; * Nombre de caractères dang le buffer *
SHORT DispCount; * nanbre de caractères visibles *
SHORT Cleft, Ctcp; * offset du container *
struct Layer *LayerPtr; * layer associé au gadget *
LOM3 Longlnt; * si un entier est saisi sa valeur est ici * struct KeyMap *AltKeyMap; * pointeur sur son propre clavier *
}
- deuxième méthode, dans la structure IntuiMessage envoyée par Intuition, il y a un champ "LAddress" qui contient l'adresse de rémetteur du message. Il suffit de tester si ce champ équivaut à l'adresse d’un des gadgets dans la liste.
If (message->IAddress == Sgadgetl)
* le gadget 1 est sélectionné *
- pour éviter une série de if à rallonge, il est possible d'utiliser le champ "GadgetlD" de la structure gadget. Pour chaque gadget, nous allons stocker dans ce champ son numéro. Comme avec la méthode précédente, nous sommes capable de récupérer l'adresse du gadget, nous pouvons sans problème récupérer son numéro, et remplacer ainsi la lourde structure à base de if, else if, par un switch beaucoup plus simple à gérer.
ÜSHORT num;
num = ((struct Gadget *) message->iAddress)->GadgetID; switch(num)
case 1: * gadgetl sélectioné *
* etc *
- ayant l'habitude d'en faire le moins possible pour arriver au résultat, j’ai rapidement trouvée le switch lourd à gérer. Or. On peut s'en passer avec un peu d’astuce. Dans la structure Gadget, nous avons un champs dénommé UserData. Ce champ pouvant contenir, ce que l'on peut veut, pourquoi ne pas lui faire contenir l’adresse de la fonction qui va être appelée lorsque le gadget sera activé ? Ce qui donne :
(*((void(*)())((struct Gadget *)message->!Address)->DserData))();
Il ne faut pas oublier de déclarer les fonctions avant de déclarer le gadget, sinon le compilateur risque de vous injurier (à juste titre d'ailleurs). Le "cast" peut sembler un peu compliqué mais en le décomposant, on comprend très vite :
- (struct Gadget *)message->IAddress correspond à l'adresse du gadget ;
- (struct Gadget *)message->IAddress->UserData correspond au champ UserData du gadget, qui est de type APTR ;
- pour le transformer en type fonction void il faut le caster en pointeur de fonction, donc :
((void(*)())((struct Gadget *)message->IAddress)->UserData)) ;
- enfin, pour exécuter la fonction, il ne reste plus qu'à récupérer son adresse qui se trouve dans UserData. D'où l’on obtient (*((void(*)0)((struct Gadget
* )message->IAddress)->UserData))() ;
Simple, non ? (Non, pas trop, je vous l’accorde).
Pour le reste des détails, je vous renvoie au programme accompagnant cet article.
Concentrons nous maintenant sur la structure particulière du gadget de saisie de chaînes de caractères. Pour créer un tel gadget, il faut indiquer dans le champ GadgetType STRGADGET et associer au champ "Speciallnfo". Une structure Stringlnfo correctement remplie. La voici commentée.
Struct Stringlnfo
ÜBYTE *Buffer; * buffer de saisie de la chaîne *
ÜBYTE *UndoBuffer; * buffer optionnel pour le ÜNDO *
SHORT BufferPos; * Position du curseur dans la chaîne *
La gestion de ce gadget est dans notre cas différente de celle d’un gadget booléen. En effet, il faut récupérer la chaîne de caractères une fois la touche [Enter] pressée, ce qui correspond à un événement GadgetUp (c’est donc dans ce cas que l'on doit effectuer la conversion). Malheureusement, lorsque l’on se prépare à saisir une chaîne, l'événement GadgetDown est aussi généré. On fait donc la différence entre les deux cas avec le nombre de caractères présents dans le "buffer". En effet, avec l'apparition du GadgetDown. Le nombre de caractères vaut 0 alors qu’avec GadgetUp, on a saisi tous les caractères, ce nombre est donc différent de zéro. C’est pas plus difficile que celà (cf. Le programme).
CONCLUSION
Une rapide conclusion car la place me manque. Pour comprendre le reste, je vous invite à étudier le programme commenté qui suit cet article, ainsi que l’Intuition Manual que vous êtes sûr de trouver chez tout bon distributeur Amiga (par exemple chez MAD. 42, rue Lamartine. 75009 PARIS. Le mois prochain, nous étudierons les gadgets proportionnels, avec comme support un autre utilitaire (c'est la surprise).
* - - ----------
* Convertisseur Héxadécimal, décimal, octal *
* Exemple de programma tion des gadgets sous intuition
* - Gadgets booléen
* - Gadgets chaîne de caractères
*
* P. AMIABLE 1991
*
*
* ----------------
* Quelques includes utiles......
* - -------------
include exec types.h>
include intuitian intuiticn.h>
include stdio.h>
include string.h>
* *
* Les defines maintenant .....*
* *
define DmjlTlON_REV 0L ‘Version de la bibliothèque »
define DEC 1 define HEX 2 (tdefine OCT 3
* Pré-déclaration pcxir les gadgets * voiddecO, hexaO, octal(), saisie_chaine();
* *
* Définition des variables externes *
. *
UBYTE bufferchaine[12];
struct Stringlnfo chaîneinfo = txifferchaine, NULL,
0, 11, 0, 0, 0, 0, 1, 1, 0, 0,
NULL
};
SHORT cadrel[] =
0, 0, 101, 0, 101, 11, 0, 11, 0, 0
};
struct Border bordure1 =
- 1,-1, 3, 0, JAM1, 5, cadrel, NULL ;
struct Gadget gadget4 =
NULL, 90, 20, 100, 10, NULL, RELVERIFY+STRINGRIGîr+ALTKEYMAP+GADGIMffiDIATE, STRGADGET, (APTR)&bordurel,
NULL, NULL, NULL, (APTR)&chaineinfo,
NULL, (APTR)saisie_chaine
Herr Docktor Von Gluten... Ie"11 ?
};
SHORT cadre2 [) =
0, 0, 31, 0, 31, 14, 0, 14, 0, 0 };
struct Border bordure2 =
- 1, -1, 3, 0, JAM1, 5, cadre2, NULL ;
struct IntuiText textl =
3, 0, JAM2, 3, 2, NULL, "oct", NOLL ;
struct Gadget gadget3 =
&gadget4, 10,85, 30,13, NULL, RELVERIFY+GADGIMMKDIATE, BOOLGADGET, (APTR)8bordure2,
NULL, fctextl, NULL, NULL, NULL, (APTR)octal };
SHORT cadre3 [] =
0, 0, 31, 0, 31, 14, 0, 14, 0, 0 };
struct Border bordure3 =
- 1, -1, 3, 0, 0AM1, 5, cadre3, NULL };
struct IntuiText text2 =
3, 0, JAM2, 3, 2, NULL, "hex”, NULL ;
struct Gadget gadget2 =
&gadget3, 10, 63, 30, 13, NULL, RELVERIFY+GAEGIMMEDIATE,
BOOLGADGET,
(APTR)&bordure3,
NULL, &text2, NULL, NULL, NULL, (APTR)hexa };
SHORT cadre4[] =
0, 0, 31, 0, 31, 14, 0, 14, 0, 0 };
struct Border bordure4 =
- 1, -1, 3, 0, JAM1, 5, cadre4, NULL ;
struct IntuiText text3 =
3, 0, JAM2, 3, 2, NULL,
"dec", NULL
};
struct Gadget gadget1 =
&gadget2, 10, 40, 30, 13,
NULL, RELVERIFY+GADGIMMEDIATE, BOOLGADGET, (APTR)&bordure4,
NULL, &text3, NULL, NULL, NULL, (APTR)dec };
struct IntuiText textdec =
3, 0, JAM2, 50, 41, NULL,
NULL
};
struct IntuiText texthex =
3, 0, JAK2, 50, 64, NULL,
&textdec
};
struct IntuiText textoct =
3, 0, JAM2, 50, 86, NULL,
Stexthex
};
struct IntuiText texttyp =
3, 0, JAM2, 10, 20, NULL,
"Décimal",
Stextoct
};
struct NewWindcw nouvf enetre =
202, 146, 200, 110, 0, 1,
GADGETDCHN+GADGSTUP+CLOSEWINDCW,
WINDCWDRAG+WINDCWDEP'IH+WINDCW3LOSE
+ACTTVATE+NOCAREREFRESH,
fcgadgetl,
NULL, "Convertisseur", NULL, NULL,
200, 110, -1, -1,
WBENCHSCREEN )î
' *
* déclaration des variables globales *
* ...- *
struct GfxBase ‘GfxBase = NULL; struct Intuit ionBase 'IntuitionBase = NULL; struct window 'fenetre = NULL; struct RastPort 'rastport = NULL; int typecorrv = DEC;
¦*
*
¦*
* -----
* Progranme principal
» ------
voie main()

struct IntuiMessage "message; long GetMsgO;
ULON3 classemessage; char chainevide[12] = " ";
void init(),ouvrefenetre(),referme();
init();
ouvrefenetre(); rastport = fenetre->RPort;
PrintIText(rastport,&texttyp,0,0);
while(l) * boucle infinie *
message = (struct IntuiMessage *)
GetMsg(fenetre->UserPort); if(message) * y-a-t'il un message ? *
classemessage = message->Class;
* récupère la classe * ReplyMsg(message); * libéré le message *
if (classemessage == CLOSEWINECW)
* fermeture ? *
referme(); * on ferme tout *
exit(TRUE); * et on sort tranquillement *
* GAEGEIDOWJ -> booléen eu string gadget activé * * GAEŒ7IUP -> [Bfter] dans le string gadget * if(classemessage == GADGETDCWN II classemessage == GADGEIUP)
strepy(textoct.IText,chainevide); strepy(texthex.IText,chainevide); strepy ( textdec. Itext, chainevide ) ;
PrintIText(rastport,Stexttyp,0,0);
* Appelle la fonction liée au gadget activé » (*((void(')())((struct Gadget *)
message->lAddress)->UserData))();
}
}
}
}
* -*
* InitO Oivre la bibliothèque *
* - *
void init()

char- "OpenLibrary ( ) ;
IntuitionBase = (struct Intuit ionBase *)
CpenLibrary ( "intuitico. Library", IniVJiTiCN_ REV) ; if(!IntuiticnBase)
printf("Mais où est donc passé intuition ? "); exit(FAISE);
}
)
* - -*
•ouvrefenetre() ouvre la fenetre et les gadgets*
. - *
void ouvrefenetre()

void referme();
if(!(fenetre=(struct Window* )QpenWindcw
(fcncuvfenetre)))
referme();
* *
•Cette fonction referme l'écran et la fenetre*
* *
void referme()

if(fenetre) CloseWindcw (fenetre);
i f(IntuitionBase) CloseLibrary(IntuitionBase);
}
* - *
* fonction gérant le gadget 1 *
. -*
void dec()

typeconv = DEC;
strepy (texttyp. Itext, "Décimal") ; * Affiche
1'IntuiText associé* PrintIText(rastport,fctexttyp,0,0);
}
* -.....*
* fonction gérant le gadget 2 *
*--------------------- - *
void hexa()

typeconv = HEX;
strepy(texttyp.IText,“Hexadec"); 'Affiche
l'Intuitext associé* PrintIText(rastport,Stexttyp,0,0);
}
* *
* fonction gérant le gadget 3 *
* -*
void octal()

typeconv = OCT;
strepy(texttyp.IText,"Octal "); 'Affiche
l'Intuitext associé* PrintIText(rastport,Stexttyp,0,0);
. *
'fonction réalisant le traitement de la chaîne* 'de caractères *
* *
void saisie_chaine()

if(chaîneinfo.NmnChars) * caractères dans le
buffer ? *
long num; int erreur = 0, i;
if(typeconv == HEX) * en héxa '
for(i=0;i strlen(bufferchaine);i++)
* Attention à bien saisir le nombre en najuscule *
if(bufferchaineti] '0' Il bufferchaine [i] > 'F') erreur =1;
* conversion chaîne hexa -> nombre décimal * stch_l (bufferchaine, tnum) ,-
}
if(typeconv == OCT) * en octal *
for(i=0;i strlen(bufferchaine);i++) if(bufferciHine[i] '0' Il bufferciaine [i] > '7') erreur =1;
* conversion chaîne octal -> nombre décimal * stco_l(bufferchaine,&num);
if(typeconv == DEC) ' en décimal *
for(i=0;i strlen(bufferchaine);i++) if(bufferciaine[i] '0' Il buffertbaine (i] > '9') erreur =1;
* conversion chaîne deci -> nombre décimal * stcd_l(bufferchaine,&num);
}
if(îerreur) * si saisie correcte '
sprint f ( textdec. Itext, "%d", num) ; sprintf(texthex.IText,"%x",num) ; sprintf(textoct.IText,"%o",num) ;
PrintIText (rastport, Sctexttyp, 0,0) ;
)
else
DisplayBeepO; * sinon en fait flasher l'écran *
rhaineinfn-MBTfhars = 0; ' en remet tout à zéro * strepy(chaineinfo.Buffer,"¦);
Le système d’exploitation de Vamiga offre un moyen à la fois simple, efficace et pratique, au travers des bibliothèques et des devices, de gérer les différents périphériques de la machine. Il y a pourtant des cas dans lesquels Von peut avoir besoin d’accéder directement au hardware.
Le problème reste toujours le même : l'Amiga étant multitâche, accéder aux registres hardware sans prendre de précautions peut entraîner des situations, heu... disons délicates. Que diriez-vous si, alors que votre traitement de textes préféré imprime votre superbe document que vous avez passé trois heures à réaliser, un autre programme venait à s'approprier sauvagement le port parallèle pour ses propre besoins ?
C'est pour éviter ce genre d’incidents que les petits malins de chez Commodore-Amiga ont introduit la notion de "resource", ou. En français dans le texte, de... ressource, mais oui Madame, c'est encore un militaire qui gagne une tringle à rideaux. Dans la suite de cet article, j’utiliserai uniquement le nom anglais, "resource”, rien que pour embêter les anglophobes...
Le principe est fort simple : avant que d'anaquer le hard. On demande poliment à l'Amiga si personne d'autre n'est en train de l'utiliser, et si c'est le cas. On se l’approprie égoïstement, interdisant par la suite aux autres tâches d'y accéder. Ce qui me fait préciser tout de suite qu’évidemment, il ne faudra pas oublier de le libérer après usage, sinon pan-pan cul-cul.
Il n'existe pour l’instant que quatre resources officiellement supportées : la disk.resource. la cia.resource. la misc.resource et la potgo.resource.
OUVERTURE D’UNE RESOURCE
Tout comme une librarie ou un device. Une resource doit être ouverte au moyen d'une fonction d'Exec appropriée, qui s'appelle devinez comment ? OpenResourcef). Oui. Son synopsys est le suivant :
Résultat = OpenResourcef ResourceName. Version) dO.L -498 al dO.L
(dans la suite de cet article, tous les exemples seront donnés en assembleur, qui reste tout de même le langage le plus pratique pour accéder aux resources)
- Résultat : adresse de base de la resource, ou 0 si erreur :
- ResourceName : pointeur sur son nom. Terminé par 0 :
- Version : numéro de version de la resource :
Remarquez la similitude à peine voulue avec OpenLibraryQ...
On accède ensuite aux fondons de chaque resource via son adresse de base, comme pour une bibliothèque standard.
Par contre, à la différence d'une bibliothèque, on ne referme pas une resource (la fonction CloseResourceO n’existe pas !). La raison en est simple : une et une seule tâche peut à un moment donné, posséder une resource : il est donc inuüle, comme c’est le cas pour une bibliothèque, de maintenir un compteur de "clients" avec des variables et des zones de données propres à chacun d’entre eux. L'ouverture d'une resource consiste simplement pour celle-ci à vérifier que personne ne la possède déjà et à retourner le cas échéant son adresse de base, un point c'est tout.
Attenüon : ouvrir une resource ne suffit pas pour y accéder ! Il faut ensuite se l'approprier grâce à ses fonctions propres.
Re-attention : une resource n'est finalement rien d'autre qu'un protocole d'utilisation du hardware dans un environnement multitâche. Rien de physique n'interdit l’accès aux registres hardware (adresses SDFFxxx) directement par un programme. C'est de la responsabilité du programmeur.
’AMIGA A DE LA
que de respecter ou non ce protocole.
DISK.RESOURCE
En voilà une qui n’est que rarement utilisée. Non pas qu'elle ne présente pai d’intérêt particulier, mais bon. La gestion directe des lecteurs de disquettes sur l'Amiga étant un tel bordel, autant laisser celà au trackdisk.device. qui s'en débrouille d’ailleurs fort bien.
Le premier problème vient du fait que le trackdisk.device s'appropria lui-même la resource de chaque drive connecté, et ne la libère jamais, chaque lecteur étant, théoriquement, en permanence disponible pour le système.
Nez en moins, la disk.resource offre deux paires de fonctions poui s'approprier libérer une unité donnée. Le couple AllocUnitf) et FreeUnitf est utilisé lorsque le lecteur en question n'a pas encore reconnu par le système. Un exemple typique est un device devant gérer un lecteui particulier (5" 1 4 ou 3" par exemple) : le device est chargé par la commande Mount de la Startup-Sequence, il réserve la resource, et le système, par cette même commande Mount, prend connaissance de la présence de ce drive particulier.
D'un autre côté. GetUnitO et GiveUnit() sont utilisées pour momentanémeni piquer la resource au trackdisk.device. J'insiste sur le moi "momentanément", parce d'autres tâches (le Shell en particulier) peuveni vouloir accéder au drive concerné. Cette solution est vivement déconseillée, au profit de celle utilisée par Frédéric Mazué dans son programme anti-click de TANT ncXXX (inhibition du lecteur au moyen d'un DosPacket de typt ACTION_INHIBIT et utilisation du trackdisk.device). Cette seconde solution garantit de plus une compatibilité totale avec d’éventuelles futures extensions du hardware-disquette.
LA CIA.RESOURCE
Les deux chips 8520, plus connus sous le nom de CLA-A et CIA-B, qui équipent l'Amiga fournissent chacun trois timers de grande précision. Là encore, le timer.device se charge d'établir une passerelle entre vous et le hardware. Cependant, une utilisation en multitâche peut conduire à de; timings erronés, notamment lorsque le système est très occupé (beaucoup de tâches tournant simultanément, dont certaines avec une priorité élevée) Cette relative imprécision est bien entendu inacceptable pour certaines applications, qui devront alors recourir à la ciaresource.
L'avantage est qu'un programme utilisant cette resource, à directement accès aux interruptions provoquées par les timers des CIAs. Il s'agit là d'interruptions matérielles, et non logicielles, comme celles provoquées - e chainées - par le timer.device.
Les fonctions offertes sont AddlCRVectorf), qui installe le vecteut d'interruption. SetlCRQ et AblcICRO, qui accèdent au registre ICR des CIA (note : le propos n'étant pas ici de faire un cours complet sur le 8520. Reportez-vous à la littérature spécialisée, à savoir le Hardware Manual ou h Bible de l’Amiga). Et RemICRVector(), qui enlève le vecteur d'interruptior lorsqu'on n’en a plus besoin.
Note : en réalité, seul le CIA-B est disponible, le CIA-A étant intensivemeni utilisé par le système. La tableau ci-dessous résume l'emploi de chacun des deux CIAs par l'Amiga (rappel : le CIA-A déclenche une interruption dt niveau 2 et le CIA-B. Une interruption de niveau 6) :
CIA-A (IRQ 2)
CIA-B (IRQ 6) non utilisé non utilisé graphies.library
Timer A Handshake clavier Timer B timer.device MICROHZ TOD timer.device VBLANK
L’EXEMPLE
Le programme assembleur qui suit, utilise la cia.resource pour s'appoprier 1 timer B du CIA-B. Et changer la couleur 1 suivant une palette prédéfinie, tous les l 50èmes de seconde. Ce type de programme est évidemment plus adapté avec l'interruption VBLANK (IRQ 3). Mais c'est la seule idée que j’ai eue. En dehors de l'inévitable et très banal chronomètre. Le source esi sufisamment commenté pour que je puisse me permettre de vous quitter sans de plus amples explications et vous donner rendez-vous au mois prochair pour la suite (et la fin) de notre tour d’horizon des resources.
RESOURCE ! Par Max 1 ?
Move.l
message,d2
* Escesnple d'utilisation de la cia.resource. Utilise le tinter A du *
move.l
messlen,d3
• CIA-B pou- faire clignoter la couleur 0 (c'est pas très joli, vu *
CALLDOS
Write
* que le
ohangemern
de couleur n'est pas synchro avec le VBL, mais *
* bon, ça
narche, on n'en demande pas plus...).
. *******
* (c) 1991, Max pour 1'Amiga News-Tech *
move.b
$ 80+CIAICRF_TA,dO
CALLCIA
SetlCR
incdir
"include:"
include
"exec interrupts.i"
Attend
move.l
SIGBREAKF_CTRL_C,dO
include
"exec exec_lib.i"
CALLEXEC
Wait
include
"1ibraries dos.i"
include
"libraries dos_lib.i"
; *******
include
"hardware cia.i"
Exit
moveq
ÜCIAICRB_TA,dO
include
"resources cia.i"
lea
Inter(pc),al
CALLCIA
RemlCRVector
opt
o+, ow-
. *******
. *******
Occupe
move.b
oldmask(a5),dO
_LVOAddICKVector
EQU -$ 6 ; Bit(dO) Interrupt(al)
ext.w
dO
_LVORemICRVector
EQU -$ c ; Bit(dO) Interrupt (al)
bset
7,d0 ; bit 7=1 -> set
_LVQAbleICR
EQU -$ 12 ; Mask(dO)
CALLCIA
SetlCR
LVOSetlCR
EQU -$ 18 ; Mask(dO)
. *******
NoCIA
move.l
_DOSBase(pc),al
CALLCIA
MACRO
CALLEXEC CloseLibrary
move.1
ClABase(a5),a6
jsr
_LVDl(a6)
NODOS
moveq
0,d0
ENEM
rts
CIAA
EQU
SbfeOOl
CIAB
EQU
SbfdOOO
; * Serveur d'interruption pour le CIA-B Timer A.
; * En entrée, al
contient le champ IS_DATA de la structure *
rsreset
* Interrupt mise en place.
Stdout
rs.l
1 ; Renvoyé par OutputO
ClABase
rs.l
1 ; Renvoyé par OpenResource()
Cialnt
move.w
counter(al),d0
ciavect
rs.l
1 ; Renvoyé par AddlCKVector()
addq.w
l,d0
oldmask
rs.w
1 ; Renvoyé par SetICRO
cnpi.w
NbColor,dO
counter
rs.w
1 ; Compteur de couleurs
bcs.s
.Encore
VARSIZE
rs.w
0
moveq
0,d0
.Encore
move.w
dO,counter(al)
. .
C'est parti ! *
add.w
d0,d0
lea
Colors(pc),al
move.w
(al,d0.w),$ dffl80
Start
lea
VARS(pc),a5 ; Adresse des variables
bset.b
0,CIAB+ciacra ; Relance le Timer
lea
dosname(pc),al ; Ouvre la 'dos.library'
moveq
0,d0
moveq
0,d0 ; Positionne Z
CALLEXEC
OpenLibrary
rts
move.1
dO,_DOSBase
beq
NoDos
; ******
VARS
dcb.b
VARSIZE,0
CALLDOS
Output
move.l
dO,stdout(a5)
; structure Interrupt
Inter
de. 1
0 ; is_Node.ln_Succ
lea
cianame(pc),al ; Ouvre la 'ciab.resource'
dc. l
0 ; is_Node. Ln_Pred
moveq
0,d0
de .b
OT_INrERRUPT ; is_Node.ln_Type
CALLEXEC
OpenResource
de .b
1 ; is_Nbde.ln_Pri
move.l
dO,ClABase(a5)
dc. l
myname ,- is_Node. Ln_Name
beq
NoCIA
dc. l
VARS ; is_Data
dc. l
Cialnt ; is_Code
lea
CIAB, a4 adresse du CIA-B dans a4
_DOSBase
dc. l
0
moveq
CIAICRF_TA, dO ; bit 7=0 -> clear
; ******
CALLCIA
SetlCR
Colors
de .w
$ 000,$ 111,$ 222,$ 333,$ 444,$ 555,$ 666,$ 777
move.b
dO,oldmask(a5) ; sauve l'ancien masque
de .w
S888,$ 999,$ aaa,$ bbb,$ ccc,$ ddd,$ eee,$ fff
dc. w
Seee,$ ddd,$ ccc,$ bbb,$ aaa,$ 999,$ 888
* * Place notre propre vecteur d'interruption Timer A
de .w
$ 777,$ 666,$ 555,$ 444,$ 333,$ 222, $ 111
moveq
CIAICRB_TA,dO
NbColor
EQU
(•-Colors) 2
lea
Inter(pc),al
CALLCIA
AddICRVector
. ******
move.l
d0,ciavect(a5)
dosname
de .b
“dos.library",0
boe.s
Occupe ; quelqu'un l'a déjà !
Even
cianame
dc. b
"ciab.resource", 0
even
move.b
0,ciacra(a4)
nyname
dc. b
"Max's Resource Demo !",0
even
message
dc. b
"Pressez CIRL-C pour arrêter...",$ 0a
DELAI
EQU
14187 ; valeur pour l 50ème de seconde
messlen
EQU
• -message
move.b
(DELAI&$ FF),ciatalo(a4)
even
move.b
(DELAI»8),ciatahi(a4)
END
2SSS3S
move.l
stdout(a5),dl
S-11!!
¦ r.l'iaiij- igasasas i imai
Please insert letter HT
in m boîte postale
îequester
Fred.
Hazué
¦b
Bonjour a toute l’équipe de l’ANT ! Je vous écris pour plusieurs choses: pourriez-vous me donner une routine permettant le plus simplement possible d'afficher une image sur mon écran, qui commence à se lasser du bleu. Je possède PixMate et puis donc convertir l'IFF en RAW. Mais encore faut-il posséder une routine capable de relire ces données Bitmap et les afficher !
- autre point qui me tient à coeur en ce moment, je voudrais créer un programme assembleur à installer sur le boot de mes disks pour en lire le contenu (un "dir". Quoi !). Il m’a semblé bon de commencer par utiliser la commande Dir du CL1, pour me mettre dans le bain. J’ai donc fait un petit programme assembleur qui affiche le directory. En voici le listing :
Je suppose qu'il s'agit de l'écran du Workbench ? Deux possibilités Premièrement, sur la disquette ComRev 2 se trouve un programme qu devrait convenir. Deuxièmement, l'écran du Workbench est un écran Intuition à 2 bitplanes (4 couleurs). Il est facile de récupérer le pointeur de cet écran dans IntuitionBase. Ensuite, il suffit de savoir que le bitplanes se situent à l’offset SCO et SC4 de la structure Screen. Il ne reste plus qu'à les remplir, ces fameux bitplanes.
Ton programme ne marche pas. Car la définition de la fenêtre RAW: est mauvaise. Utilise plutôt :
dc. b "RAW: 0 10 640 200 ** dir try **",0,0
Avec ça. Le programme fonctionne. Pense quand même à fermer 1 fenêtre et la dos.library.
Il est effectivement nécéssaire d’utiliser les routines de la dos.librar) dans ce cas. Pour la fonction "print". Il y en une toute faite (et qu marche, une fois n'est pas coutume !) Dans un autre libre dt Micro-Application : "Le livre du Langage Machine".
Enfin, dans Commodore Revue N°20. Il y a un programme d'exempk écrit en relatif PC. Cela va peut-être t'aider. Peut-être publierons nous ur petit article sur cette question prochainement.
Mon cher Laurent, en plus des problèmes ci-dessus, tu en a* probablement un que tu ne soupçonne même pas : ta disquette étai infestée par le virus "Lamer II". Pas trop de "readAvrite errors" i Taverny?
; essai de directory 06.01.90 sous DEVPAC IX
openlib=
- 408
write=-48
execute=
- 222
open=-30
start
move.1
4, a 6
; ouvre DOS
lea
dosname,al
moveq
0,d0
jsr
openlib(a6)
move.1
d0,dosbase
; récupère adresse base de
DOS
move.1
nom,dl
; nom de ma fenêtre
move. 1
1005,d2
; mode ancien
move. 1
dosbase,a6
jsr
open(a6)
move.1
dû,wdhd
; récupère le Handle fenêtre
move.1
dosbase,a6
move.1
command,dl
; la commande DIR
clr.l
d2
move.1
wdhd,d3
; ma fenêtre : problème ici
? ?
Jsr
execute(a6)
loop
btst
6,$ bfe001
; teste bouton gauche souris
bne
loop
rts
; si presse alors fin
Voilà qui est fait
dosname de. B "dos.1ibrary",0 nom dc.b "RAW:0 10 640 200* command dc.b “dir”,0 dosbase dcb.l 1 wdhd deb.1 2
dir try
Mon problème est que ce directory ne s'affiche pas dans ma fenêtre, qui ne s'ouvre d’ailleurs pas du tout ! Help please !
Fidèle lecteur de votre magazine depuis l’achat d'un Amiga 2000. Après avoir fait un tour d’horizon de l’AmigaBasic (FM: que! Courage !). Je débute en C. Quelque peu isolé en Dordogne. J'aimerais avoir des contact et des conseils avec des créatifs et des passionnés. Pouvez-vou. Passer mon annonce :
- Intéressé par la programmation en C. je suis partant pour tout échangt d’informations et de programmes. Tel : (16) 53.53.58.55 aux heures de. Repas.
Je suis un fidèle lecteur (FM: ils disent tous ça !). Voilà mon problème, j'espère vraiement avoir une réponse de votre part, car je ne sais plu. Comment faire : je possède un Amiga 500 depuis plus de 3 ans et sui. Attiré par tout ce qui est programmation. J’ai donc commencé bien sia par notre cher AntigaBasic. Que je laisse de coté pour travailler avec le GFABasic. Par manque de documentation, j’ai à nouveau changé et sui. Passé sur le langage C. Idem, par manque de documentation, je me suis enfin arrêté sur le langage machine.
Donc voilà, j'ai programmé sous plusieurs langages que j’ai tour à tour laissés tomber par manque de documentation, sauf le langage machine, parce que je persiste à croire que quelqu'un viendra à mon secours, vous en l’occurence.
Dans le n c29 de Commodore Revue, il y a un lecteur qui vous demande quel documentation existe sur les routines d'intuition, Exec... et vous avez répondu qu 'il faut consulter les Amiga Rom Kernal Manuals (qui je suppose, sont en anglais) mais vous n’avez pas donné l’éditeur. Donc
- quel est l’éditeur de ces ouvrages ?
- comment faire pour s'attribuer une si belle collection ?
- sont-ils en anglais ou en français ?
Je tiens quand même à signaler que je suis allé à la FNAC, Union oi autres libraries pour me renseigner et on me répond à chaque fois la même chose : "ces livres sont inconnus".
En vous remerciant d'avance de votre précieux coup de main, je souhaite longue vie à Commodore Revue et. Bien sûr. à l’ANT.
Luc Spony (Riedisheim)
Mais revenons maintenant a mon problème initial : effectuer un dir dès le boot. Un copain m’a dit d’utiliser ExNextf) et Examine!) Car il craint que le DOS. Pas encore installé lors du boot. Ne permette pas une exploitation de la commande Dir. Un programme dans La Bible de F Amiga (page 490) accomplit cette tâche, mais je n’arrive pas à me faire une fonction "print" comme ils le disent. Là encore : Help !
Un nouveau problème se pose : il faut écrire le source en relatif PC car mon programme sera dans le boot. Mais comment faire ?
DENOUE Laurent (Taverny)
free men. 2735
Comme de bien entendu, ces très précieux ouvrages sont en anglais. Il faut savoir que 99% des programmes d'exemples donnés dans ces livres sont écrit en C, ce qui est tout-à-fait normal sur l'Amiga.
A ma connaissance, le seul endroit où il soit possible d'acheter ces ouvrages est le magasin : MAD - 42, rue Lamartine - 75009 PARIS - Tél
(1) 48.78.11.65 (n’hésitez pas à téléphoner, les RKM ne sont pas toujours disponibles). La référence exacte de ces livres est :
ROM Kernel Reference Manual - Commodore-Amiga. Incorporated Amiga Technical Reference Sériés édités par Addison-Wesley Publishing Company, Inc. - Massachusetts - USA
Une autre solution : si vous avez acheté un compilateur C (par exemple et au hasard : le SAS, ex-Lattice) et que vous êtes dûement enregistré comme client, vous pouvez écrire pour leur demander s'ils accepteraient de vous vendre ces bouquins. C’est tout-à-fait possible, et vous pouvez être sûr en tout cas qu’ils répondront à votre courrier très rapidement. Enfin, ultime solution, vous écrivez un programme génial, vous gagnez le concours-lecteurs mensuel et vous recevez notre DevKit qui comporte, il n’est pas inutile de le rappeler :
- l’assembleur Devpac II
- le compilateur C SAS 5.10
- tous les Rom Kernel Manuals (3 volumes).
Alléchant non ?
Bonjour à toute la rédaction. Si je vous écris, c'est pour vous dire que j’apprécie beaucoup l’ANT, et plus particulièrement la rubrique AMOS de François Lionet. Toutefois, j’aimerais que vous parliez un peu plus de ce super-langage dans le Requester (je présume que vous devez tout de même recevoir quelques lettres à ce sujet, non ?). En tout cas. En voici au moins une.
Je me suis récemment procuré une démo du groupe Syntex, entièrement réalisée en AMOS (j’en profite pour les féliciter publiquement de leur travail !). J’ai voulu lancer l’une de ces démos directement depuis l’éditeur d’AMOS. Outre le fait que le programme est protégé, j’ai oublié de recopier sur mon disque dur quelques fichiers, ce qui a provoqué une erreur "File not found"... et planté AMOS, qui restait bloqué sur ce message et ne me rendait pas la main. Je voudrais donc savoir si ce problème survient de la protection du programme, ou si c 'est ma version d’AMOS qui est buggée ?
Jerôme Marchand, alias Mr. Perfect
Merci pour les compliments... Pour ce qui est d’AMOS dans le Requester, nous préférons que François Lionet réponde lui-même à son courier. Les lettres concernant AMOS lui sont donc transmises. Mais le plus simple - et le plus rapide - est encore d’utiliser le Minitel, en allant sur le 3615 COMREV, rubrique ANT, où François dispose d'une BAL et d’une tribune pour lui tout seul !
Quant à votre problème avec la démo de Syntex. Rassurez-vous il n’est pas dû à un bug de l’interpréteur AMOS. Mais bel et bien à la démo elle-même. En effet, renseignement pris auprès d'Alcatraz de Syntex. Il inhibe plusieurs sources d’interruptions, dont le clavier, histoire de gagner du temps pour la VBL. Conclusion : lorsqu’une erreur quelconque survient, le clavier n’est pas rétabli, et AMOS attend indéfiniment qu’une touche soit appuyée.
Puisqu’on parle d’AMOS, restons-y : à partir de ce numéro de l’ANT. Chaque disquette contiendra une mini-démo en AMOS écrite par Daisy, la chienne de François ! Il s’agit de petites routines produisant toutes des effets sympas à l’écran... et dont le source n’est pas protégé, lui ! De plus, en cadeau-bonus et avec l’accord de Syntex, la disquette de ce mois-ci contient l’une de leur démo.
Bonjour. Cette lettre s’adresse plus particulièrement à Max, puisque c’est bien lui de spécialiste de l’assembleur de l’ANT, non ? Elle concerne non pas le langage-machine, mais bien le 68000 lui-même. Voici de quoi il retourne.
J’ai essayé d’adapter le programme du "RKM Libraries and Devices", dans le chapitre sur le timer.device, page 876, qui calcule l'heure système (heures, minutes, secondes) à partir des données fournies par le device. Tout se passe bien jusqu'aux calculs eux-mêmes, qui sont totalement faux (alors qu’avec le programme C. ils fonctionnent très bien !). Après traçage, je me suis aperçu que c 'était l'instruction DIV du 68000 qui buggait : dO.l contenant le dividende (égal au nombre de secondes écoulées depuis le 1er janvier 1978 !) Et dl.w contenant le diviseur (60 ou 24 suivant que l'on calcule les heures, minutes ou secondes), l’instruction DIVU DI.DO laissant les deux registres inchangés ! Le bit V de CCR étant également positionné, j'en déduis qu 'un débordement quelconque a eu lieu à un moment ou à un autre, mais je ne sais pas comment remédier à cette situation. Un petit coup de main serait le bienvenu...
François Grandjean, Nanterre
Votre analyse du problème est tout-à-fait correcte : c'est bien le débordement qui est la cause du "mal-fonctionnement” de l'instruction
DIV. Celà dit. Il ne s’agit pas d’un bug du 68000. Mais d'une situation parfaitement connue et prévue par Motorola.
Le débordement apparaît lorsque le quotient ou le reste de la division, dépasse les 16 bits, ce qui est bien le cas ici (dO contenant une valeur supérieure à 416 millions !). Il n'y a malheureusement pas 36 manières d'y remédier : il faut écrire une routine se chargeant de gérer ce cas particulier, par plusieurs divisions successives (ce qui soit-dit en passant, prend encore plus de temps que la seule instruction DIV). D'ailleurs, si vous aviez également tracé le programme C compilé, vous auriez tout de suite vu l'astuce ! La routine qui suit est adaptée de celle proposée par Madame Viellefond. Dans son excellent livre paru aux éditions Sybex : "Mise en oeuvre du 68000". Elle attend le dividende dans dO.l. le diviseur dans dl.w et utilise les registres d2 et d3 commes mémoire tampon. En sortie. DO.l contient le quotient et d 1.1 le reste.
; Divise dO.1 par dl.w en tenant compte ; d'un éventuel dépassement de capacité.
BigDiv
divu
dl,d0
bvc.s
Resuit
movem. 1
d2-d3,-(sp)
nove.1
d0,d2
clr .w
dO
swap
dO
divu
dl, dO
move.w
d0,d3
move.w
d2,d0
divu
dl, dO
move.1
d0,dl
swap
dO
move.w
d3,d0
swap
dO
clr. W
dl
swap
dl
movem. 1
(sp)+,d2-d3
rts
Voilà. Vous ne m’en voudrez pas si je n’ai pas la place de commenter plus avant cette routine. Un conseil si vous voulez comprendre son mode de fonctionnement : tracez-la !
OU SONT LES CLUBS ?
Clubs Amiga, faîtes-vous connaître. L'Ant serait heureux de vous recevoir. Nos pages vous sont ouvertes, laissez-y votre adresse, mais aussi quelques routines ou programmes afin que les Amigafans se rendent compte de quoi vous êtes capables. Allez, écrivez-nous !
M
mm
Développer un logiciel d'envergure pour l'Amiga n ’est pas toujours chose évidente. Des erreurs peuvent être commises sans même que le programmeur ne s’en rende compte. Ce petit guide devrait vous permettre de repérer les erreurs les plus fréquentes.
Mais d'abord, quelques mots sur la manière de bien tester vos programmes. Il existe dans le domaine public et dans le commerce plusieurs logiciels spécialiés. Comme MemWatch. WatchMem. GO.MF ou TaskX. Utilisez-les avec circonspection. Testez vos programmes sur plusieurs configurations différentes (mémoire, processeur, extensions...). N'oubliez pas. Au cas où votre logiciel est appelé à être diffusé internationalement, que les claviers changent de pays en pays. Ceux qui utilisent le flag RAWKEY auront avantage à utiliser la fonctoin RavvKeyConvertO du console.device. Aux Etats-Unis, le système NTSC ne laisse "que" 200 lignes de résolution, pensez-y !
Audio - friture sur la ligne !
Les données sonores doiv ent se trouv er en Chip Ram ! Vérifiez les directives de compilation de votre compilateur, ou bien allouez dynamiquement de la mémoire Chip et recopiez-y vos données.
Messages d'erreur du CLI
Ils sont causés par un appel à e. it() avec un paramètre incorrect. Les programmeurs en assembleur doivent placer une valeur valide dans le registre dO. Les codes de retour possibles sont définis dans libraries dos.h et
i. D'autres valeurs (-1 par exemple) provoquent des messages erronés, comme "not an objet module".
La fenêtre CLI refuse de se refermer
Une fenêtre CLI ne se fermera pas. Tant qu'un programme détiendra un Lock sur son canal d'entrées-sorties ("*"). Si votre programme est exécuté par RUN >NIL:. La fenêtre pourra être fermée, à moins que voue code n'ouvre explicitement
Plantage et corruption de la mémoire
Les erreurs d'adresse, de bus. Les instructions illégales, sont généralement causées par l'utilisation d'un pointeur non ou mal initialisé. Ou déjà libéré ( FreeMem. Close...). Il est également possible que vous écrasiez par erreur une zone de données, ou que vous incrémentiez un pointeur utilisé plus tard pour FreeMem ou Close. Testez explicitement toutes les valeurs renvoyées par les fonctions du système. Vérifiez que vous ne provoquiez pas de dépassement de capacité de la pile dans vos fonctions récursives.
Un plantage peut également survenir en passant de mauvais arguments à une fonction du système, par exemple SetAPen(3) ou SetAPen(windovv.3) au lieu de SetAPen(rastport.3). Utilisez les protoypes de votre compilateur ! Plantage APRES exécution
Si un plantage ne survient que lorsque v otre programme est lancé depuis le Workbench, c'est certainement parce que vous appelez UnLockQ avec l'un des Loeks du WBStartupMessage. Ou peut-être effectuez-vous une sonie (avec printfO ou autre) sans qu’une fenêtre n'ait été ouverte pas votre Startup-Code i.
Si le plantage survient aussi bien depuis le Workbench que depuis le CLI. Vous libérez sans doute deux fois une zone de mémoire ou bien quelque chose que vous n’aviez pas obtenu. Si votre programme utilisé un device quelconque, assurez-vous avec ChecklOO. WaitlOÔ et AbortlOf ) qu'aucune requête n'est lancée quand vous quittez.
Plantage avec d'autres tâches ou les interruptions Si une partie de votre code fonctionne comme sous-tâche (avec une pile différente) ou avec la pile système, vous devez invalider l'option de vérification de la pile de votre compilateur. Si des routines de votre programme doivent être appelées par le système, asssurez-vous de choisir le modèle de données et de code LARGE avant de compiler.
Plantage avec les fenêtres
Faites attention à ne pas fermer votre fenêtre dans une boucle avec GetMsg( )
: le prochain GetMsgO utiliserait un pointeur sur un MsgPort invalide. Utilisez ModifvIDCMP(NULL) avec prudence, surtout si vous partagez un même UscrPort entre plusieurs fenêtre (Modify IDCMP(NULL) libère le MsgPort associé à la fenêtre). Enfin, soyez sûr de bien enlever les menus de votre fenêtre avec ClearMenuStripO av ant de la fermer.
Plantage seulement sur 68020 68030
Ceci peut être du à l'utilisation des 8 bits de poids fort des adresses, à di code auto-modifié. à l'utilisation de l'instruction MOVE TO SR. Privilégiée sur ces processeurs (utilisez plutôt GetCC( ) d'exec.library). à Futilisatior d'une pile erronée lors d'interruptions...
Plantage seulement anciennes ROMs
Ceci survient principalement lors de l'utilisation de fonctions d bibliothèques, avec un numéro de version plus haut que celui dont dispose 1; machine. Vérifiez bien les résultats d'OpenLibraryO. Il est également interdi de sauter directement à des addresses en ROM !
Plantage sur les machines sans Fast Ram
Un appel à AllocMenK ) avec le flags ME. F_FAST positionné échouera su des machines ne disposant que de Chip Ram. Si vous n'avez pas besoin di Chip Ram. Utilisez MEMF_PUBLIC : si de la Fast Ram est disponible. 1 système vous en attribuera en priorité.
Plantage sur les machines avec Fast Ram
Les données et les buffers destinés aux Custom Chips doivent se trouver et Chip Ram : ceci est valable pour les bitplanes. Les échantillons sonores, le! Buffers pour le trackdisk. Les sprites. Les bobs, les images, les gadgets, etc Utilisez les flags de votre compilateur ou linker pour être sûr de leu: chargement en Chip Ram. Ou bien allouez-en dynamiquement et recopiez-y (ou chargez-y) vos données.
Plantage sur les machines avec l'ECS
Ceci est du à un accès à la zone des registre hardware, à une adresse nor définie ou à l'utilisation de bits non définis dans l'ancien Chip Set (mettei les bits indéfinis à 0 à l'écriture et masquez-les par AND à la lecture).
Une icône de disquette ne disparaît pas
Ce problème survient lorsqu'un ou plusieurs Locks sur des fichiers de h disquette ne sont pas libérés, ce qui se traduit également pas une perte de 2 octets de mémoire par Lock.
Perte de mémoire
D'abord, vérifiez que votre programme n'occasionne pas une "perte d mémoire" : notez le montant de mémoire disponible (affiché dans la barre d titre de l'écran du Workbench). Exécutez votre programme, testez toutes se! Fonctions puis quittez. Si la mémoire disponible est différente de ce qu'ellt était, vous avez certainement oublié de dé-allouer ou fermer quelque chose. Si vous avez chargé le Workbench avec l'option "-debug" de la commandt LoadWB. Choisissez l'option "flushlibs" du menu invisible, à droite du ment "Spécial" (cette fonction tente de fermer toutes les libraries et fontes, tous le; devices. Etc.). Si la mémoire disponible après ça est toujours différente vérifiez bien votre source, surtout sur les points cités ci-dessous. Sinon vérifiez quelle bibliothèque, fonte ou quel device vous avez oublié de fermé. Vérifiez que tous les appels à des fonctions du type open. Alloc. Get, créait ou lock sont bien suivis du close, free. Delete ou unlock correspondant. S vous utilisez ScrollRastefi) sur une fenêtre de type SUPERBITMAP dan: fournir de TmpRas, la fonction en allouera un pour vous, mais ne le libérera pas.
Perte de mémoire - CLI seulement
Attention au CTRL-C ! Si votre compilateur possède une fonction d traitement automatique du CTRL-C. Votre code de sortie ne sera pas appelé Inhibez le CTRL-C de votre compilateur et gérez-le vous-même.
Perte de mémoire - Workbench seulement
Typiquement, ceci est est du à l'échec du Workbench à libérer votre programme avec UnLoadSeg(). Utilisez, bien exit(n) et non Exit(n). Qu ignorerait la fin de votre Startup-Code et donc le ReplyMsgO qui indique ai Workbench de libérer votre programme. De plus, l’architecture multitâche de l'Amiga oblige à utiliser ForbidO avant ce ReplyMsgO.
Problèmes avec les menus
Un plantage dû à menu est la plupart du temps causé par une mauvaise gestion des messages dont le code est MENUNULL. Assurez-vou* également de bien gérer la sélection multiple grâce au champ NextSelect. De plus, ne libérez pas la mémoire d'un Menultem allouée dy namiquement, tan que le menu est attaché à la fenêtre.
Ralentissement du système
Ceci est dû à des boucles infinies (utilisez WaitO partout où c'est possibli plutôt qu'une boucle sur GetMsgO. Notamment pour le port IDCMP d'unt fenêtre), à une priorité trop élevée de votre programme ou d'une sous-tâche à des ForbidO ou Disable() de trop longue durée...
Données du trackdisk.device non transférées
Les données de la disquette sont lues par le DMA et décodées par le Blitter De fait, elles doivent être logées en Chip Ram.
(c) 1987,91 by CATS (Commodore Amiga Technical Support,
es gadgets, etc Utilisez les flags de votre compilateur ou linker pour être sûr de leu: chargement en Chip Ram. Ou bien allouez-en dynamiquement et recopiez-y (ou chargez-y) vos données. Plantage sur les machines avec l'ECS
Ceci est du à un accès à la zone des registre hardware, à une adresse nor définie ou à l'utilisation de bits non définis dans l'ancien Chip Set (mettei les bits indéfinis à 0 à l'écriture et masquez-les par AND à la lecture).
Une icône de disquette ne disparaît pas
Ce problème survient lorsqu'un ou plusieurs Locks sur des fichiers de h disquette ne sont pas libérés, ce qui se traduit également pas une perte de 2 octets de mémoire par Lock.
Perte de mémoire
D'abord, vérifiez que votre programme n'occasionne pas une "perte d mémoire" : notez le montant de mémoire disponible (affiché dans la barre d titre de l'écran du Workbench). Exécutez votre programme, testez toutes se! Fonctions puis quittez. Si la mémoire disponible est différente de ce qu'ellt était, vous avez certainement oublié de dé-allouer ou fermer quelque chose. Si vous avez chargé le Workbench avec l'option "-debug" de la commandt LoadWB. Choisissez l'option "flushlibs" du menu invisible, à droite du ment "Spécial" (cette fonction tente de fermer toutes les libraries et fontes, tous le; devices. Etc.). Si la mémoire disponible après ça est toujours différente vérifiez bien votre source, surtout sur les points cités ci-dessous. Sinon vérifiez quelle bibliothèque, fonte ou quel device vous avez oublié de fermé. Vérifiez que tous les appels à des fonctions du type open. Alloc. Get, créait ou lock sont bien suivis du close, free. Delete ou unlock correspondant. S vous utilisez ScrollRastefi) sur une fenêtre de type SUPERBITMAP dan: fournir de TmpRas, la fonction en allouera un pour vous, mais ne le libérera pas.
Perte de mémoire - CLI seulement
Attention au CTRL-C ! Si votre compilateur possède une fonction d traitement automatique du CTRL-C. Votre code de sortie ne sera pas appelé Inhibez le CTRL-C de votre compilateur et gérez-le vous-même.
Perte de mémoire - Workbench seulement
Typiquement, ceci est est du à l'échec du Workbench à libérer votre programme avec UnLoadSeg(). Utilisez, bien exit(n) et non Exit(n). Qu ignorerait la fin de votre Startup-Code et donc le ReplyMsgO qui indique ai Workbench de libérer votre programme. De plus, l’architecture multitâche de l'Amiga oblige à utiliser ForbidO avant ce ReplyMsgO.
Problèmes avec les menus
Un plantage dû à menu est la plupart du temps causé par une mauvaise gestion des messages dont le code est MENUNULL. Assurez-vou* également de bien gérer la sélection multiple grâce au champ NextSelect. De plus, ne libérez pas la mémoire d'un Menultem allouée dy namiquement, tan que le menu est attaché à la fenêtre.
Ralentissement du système
Ceci est dû à des boucles infinies (utilisez WaitO partout où c'est possibli plutôt qu'une boucle sur GetMsgO. Notamment pour le port IDCMP d'unt fenêtre), à une priorité trop élevée de votre programme ou d'une sous-tâche à des ForbidO ou Disable() de trop longue durée...
Données du trackdisk.device non transférées
Les données de la disquette sont lues par le DMA et décodées par le Blitter De fait, elles doivent être logées en Chip Ram.
(c) 1987,91 by CATS (Commodore Amiga Technical Support,

Click image to download PDF

AMIGA NEWS TECH numero 22 (05-1991)

Merci pour votre aide à l'agrandissement d'Amigaland.com !


Thanks for you help to extend Amigaland.com !
frdanlenfideelhuitjanoplptroruessvtr

Connexion

Pub+

36% 
15.8% 
6.6% 
4.9% 
4.4% 
3.5% 
3.1% 
2.5% 
1.6% 
1.3% 

Today: 73
Yesterday: 87
This Week: 446
Last Week: 630
This Month: 2422
Last Month: 3072
Total: 66562

Information cookies

Cookies are short reports that are sent and stored on the hard drive of the user's computer through your browser when it connects to a web. Cookies can be used to collect and store user data while connected to provide you the requested services and sometimes tend not to keep. Cookies can be themselves or others.

There are several types of cookies:

  • Technical cookies that facilitate user navigation and use of the various options or services offered by the web as identify the session, allow access to certain areas, facilitate orders, purchases, filling out forms, registration, security, facilitating functionalities (videos, social networks, etc..).
  • Customization cookies that allow users to access services according to their preferences (language, browser, configuration, etc..).
  • Analytical cookies which allow anonymous analysis of the behavior of web users and allow to measure user activity and develop navigation profiles in order to improve the websites.

So when you access our website, in compliance with Article 22 of Law 34/2002 of the Information Society Services, in the analytical cookies treatment, we have requested your consent to their use. All of this is to improve our services. We use Google Analytics to collect anonymous statistical information such as the number of visitors to our site. Cookies added by Google Analytics are governed by the privacy policies of Google Analytics. If you want you can disable cookies from Google Analytics.

However, please note that you can enable or disable cookies by following the instructions of your browser.

Visitors

Visite depuis
03-10-2004
Visite depuis
23-02-2014