Sponsors

FacebookTwitterGoogle Bookmarks

SECTORISATEUR ? Un rapide rappel sur le but et l'utilité de ce programme : présenté dans l'ancienne rubrique ViewPort. Dans laquelle des éditeurs livraient leurs astuces de programmation, et programmé par Jean-Pierre Vitulli. Sectorise permettait d'écrire sur une suite de secteurs de la disquette placée en DFO:. Par le biais du trackdisk.device, un fichier AmigaDOS quelconque (image, musique, programme exécutable...). PREPARATIFS De quoi a-t-on besoin pour "transformer" un programme C en son équivalent assembleur ? Tout simplement d'un bon assembleur. J'entends par là "macro-assembleur", c’est-à-dire capable de jongler avec des fichiers includes et. éventuellement, de produire un code linkable plutôt qu’exécutable. Comme vous devriez maintenant en avoir l'habitude, c'est le Devpac II qui a été choisi, mais l’assembleur du Lattice, le DP a68k ou même l'ancêtre Metacomco feront l'affaire. Un peu de documentation ne fera pas de mal non plus et pour une fois, la Bible de l'Amiga (deuxième édition, celle à la couverture bleue) conviendra parfaitement. Mes précédents articles dans l'ANT (utiliser amiga.lib, mélange C assembleur) ne seront non plus pas de trop. Quelques connaissances, même rudimentaires, du langage C seront également les bienvenues. PROBLEMES A quel type de problème se heurte-t-on dans ce cas-là ? Le plus gros concerne les structures du C. intensivements utilisées sur l'Amiga. En effet, alors que le compilateur C sait d'office la taille des champs des structures, l’assembleur ne la connaît absolument pas. Et qui plus est. Ne se plaindra pas le moins du monde si vous référencez un mot long alors que le champ est de la taille d’un octet. D'où futilité de la documentation dont il est question dans le paragraphe précédent.

Click image to download PDF

AMIGA NEWS TECH numero 24 (07-08-1991)

Document sans nom LANGAGE
Arexx : la voie royale III par F.G. (p.2) Amos connait la musique, par F.L. (p.4)
EXECBASE
ExecBase I : du C à l’assembleur, par D.J.
(p.6)
ExecBase II : le 68000 de A à Z fin, par L.F. (P-24)
TOOLBOX
ToolBox : reqlib et parnet, par S.S. (p.18)
SUB.way
SUB.way I : la communication inter-tâches, par M. (p.16j
SUB.way II : les menus sous intuition, par HDV... (p.26)
DEMO-MAKERS
La 3D faces cachées, par J.E. (p.10)
CONCOURS
De mal en PI, par A.C. et
F. M. (p.13)
HARDWARE
Les disques chouettes, par L.F. (p.9)
UTILITAIRE
Sauveur d’écrans IFF, par M. (p.20)
Denise,
Dessin
de
Rimasson
REQUESTER 30 CATS 32
Ce numéro 24 de l’Amiga News-Tech a été tiré à 3000 exemplaires (2895 abonnés enregistrés le 07.06.91).
Ce magazine est une publication Commodore Revue Sari. 5. Rue de la Fidélité - 75010 PARIS.
Edito
Numéro 24 : deux ans (déjà !) Que rAmiga NewsTech existe. Que d'évolution en deux années.
OURS
Lwniiga New sTcch est une pubkcancn de GjmnxxJorc Revue S ARI. Dont nous
n'avez pss 5 ienreûtrc k cipna!. Non nais, bande de petits curieux, est-ce que je vvvi» demande le montant de votre coaipe en tarkjut. Ire». Hein ? Par contre, son adresse, sous pouvez U connaître : c'est le 5. Rue de la Fidc'lità. 75010 Paris. Le bisophonee-ale Ç!)4:4b92 >U.
I £ Mosieur qui signe les chèques à o tupi de lancc-piorc s'appuie Jean-Yves Primas : c'est le directeur de la puhhcatkn. Vous pouvez uxçwris l'appvrlcr au 1:1)42471 216. Mas évitez de lui parier football, il est inconsolable depuis la défete de 10..M en Cijuped'Euritpe.
Et puisqu'il lait bien un Rédac;cur-cn-Ch«. C'est Yves Hiritric qu'un a choisi. Alors qu'il était au bord du stiiad: à cause d'Ayrton Sennaqui n'arrete pas de gagner. Pour se changer les idées, il fait l'ANT en PAO sur un Amiga 2U0Ü équipé d'un Fhcker Fixer, d'une carte 68020 et de Pwfcsicnal Page 2.0 o espère que les Williams-Rcnault vieairort mettre un peu de piquant dare. Un championnat jusqu'ici bien tri-tc.
Quand Yves ne l'ait pis de PAO. Il prend tût malin plaisir a modifier les chemins tfc fer que son adjoint. Stéphane Schrciber. Ru-se des heures à fignoler avec teotkes-Æ et pission. Quand il ne va nas s'éclater au squash av ce les copains.
Pour écrire les articles, on rah appel à des pigistes qui connaissent bien leur sujet et qui sont tcBcmOT paxsioncs d* Amiga qu* ils oublient de rûler quand on les paye en retard. Ce sont : Pascal Amiable. Jérôme Etienne. Ltic Far. François Gueugnon. Denis Jairil, Frenp.'is I kmet et Max.
Les ahenrements sont gérés par la xciic MCM Europe, que vous pouvez appeler au ( 1)4.» 789210 si d'aventure vous aviez un quelconque problème de livraison. Si wxis préfirrez taire ça de manière officielle. écris ez ai 1. Quai Jean-Bapdsîe CfiânenL 94140 Alfcrtville.
Notre gentil ftasteur se nomme Cetor Wav et habite la même adresse que nous, ce qui. Il faut bien l'avouer. Nous arrange bien. Son numéro de téléphoné est le (1140708-787.
Quant à l'imprimeur. Il s'appelle N. 1. C. habite Rcuns. Travaille vite et bien et est joignable au
06) 260 5787.
Bon. On va pas s'éterniser, je voulais ju-te remercier Jean-Loip et Mathieu tf avoir pjilé île nou» dans un récent numéro de Tilt, Georges ifc bientôt parier de nous dan» un
Çrochain numéro de licro-New-s. Y van. Francoi» et Pierre de parier (.enfin !ide l'Ami aa dans SVM. Et Mknd de m'avoir ù.-mplètcmenl igmxé la tfcmière fois qu'on s'esj aoisé sur k' sand de Joystick. Ingrat
D'abord un petit cahier ait sein de Commodore Revue, puis un véritable 'journal dans le journal" pour finalement devenir indépendant... Je sais pas pour vous, mais moi, je suis curieux de voir ce que nous réseixent les prochaines années.
Tiens, un mini-sondage : y'a rien à découper. Rien à gagner, juste un petit mot à nous glisser dans votre prochain courrier, quand vous aurez le temps.
Une version française des Rom Kemal Manuals, que l'on trouverait facilement, vous intéresserait-elle ? Si oui, soyez nombreux à nous en parler, et on pourra peut-être faire quelque chose.
Voilà. Je laisse la parole à notre service comptabilité, qui a plein de propositions alléchantes à vous communiquer.
Stéphane Schreiber
ABONNEM-ANT
Prix de l’abonnement à l’ANT
- 11 numéros seuls 350,00 F
- 11 numéros + disquette 600,00 F (Etranger et DOM-TOM : ajouter 85,00 F *)
Anciens numéros
- 1 ancien numéro 40,00 F
- 1 disquette d’ancien numéro 40,00 F
- 1 ancien numéro + disquette 75,00 F
Frais de port : 8,00 F par commande. (Etranger et DOM-TOM : ajouter 10.00 F ; frais de port : 10,00 F par commande *)
* Etranger : Du fait des frais bancaires sur les chèques hors-francs, seuls les paiements par mandat international sont acceptés.
L’instruction PARSE que nous avions entrevue précédemment, mérite une analyse fouillée parce qu’elle est d’une part constamment utilisée et joue un rôle important dans l’acquisition et le traitement des chaînes de caractères (seuls objets connus d’ARexx) et parce que, d’autre part, elle présente des possibilités optionnelles nombreuses et variées.
Ll L’instruction PARSE fournil un mécanisme pour extraire une ou 7 plusieurs sous-chaînes d’une chaîne source et pour les assigner à des variables qui pourront être utilisées par la suite au gré du programmeur. L’instruction PARSE est composée de trois parties ¦ distinctes et indépendantes, et peut, de façon formelle, s'écrire :
PARSE source traitement
Le mot réservé PARSE. écrit en majuscules, identifie l'opération. La partie 'source' détermine l'origine de la chaîne de caractères qui va être traitée. La source peut être décrite par des mots réservés différents (arg, kxternal, numeric, pull, sooRCE, var, et versicn). Nous allons x revenir. La troisième partie 'traitement' décrit la façon dont la chaîne de caractères acquise depuis la source va être traitée. 11 n'y a pas ici de mots réservés mais un formalisme descriptif utilisant des règles que nous préciserons plus loin.
Un mot réserx é optionnel peut être placé tout juste après le mot PARSE. 11 s'agit du mot réserxé L’PPER. Qui transforme la chaîne acquise en majuscules axant le traitement.
Enfin, parce que cette instruction est fréquemment utilisée, il en existe des formes abréviées : PULL pour PARSL UPPLR PULL et ARG pour PARSE UPPF.R ARG. Ces formes sont synonymes, comme l'étaient ECHO et SAY décrites précédemment. Cela simplifie indéniablement l'écriture mais complique la lecture, d'autant plus qu'une fonction ARG() existe aussi. C'est pourquoi nous restons très réserxés quant à l'emploi de ces abréx ialions.
ANALYSE DES OPTIONS SOURCE
ARG : mis pour "argument", c'est l'un des moyens de passer des paramètres à un programme au moment de son invocation depuis la console. Imaginons par exemple que nous disposions d'un programme Arexx qui compte les lettres des mots qu'on lui fournit et dont le nom est CompteLettres. L'inxocation à partir de la console CLI Shell sera :
RX ConpteLeetres mot
oii mot est le mot dont on veut compter les lettres. Les premières lignes du programme CompteLettres seront donc obligatoirement pour l'option ARG : * cicre * ; c'est le début d'un progranme Arexx PARSE UPPER ARG 'traitement'
ou. En abrégé :
ARG 'traitement'
11 est tout-à-fait possible de passer ainsi plusieurs paramètres au programme. L'inxocation s'écrit alors :
RX CcmpteLettres mot_l mot_2... mot_n
On peut ainsi fournir jusqu'à 15 paramètres différents. 11 appartiendra à la partie "traitement’ du programme invoqué, de trier les mois. Pour l'instant, il suffit d'écrire les mots avec un espace entre eux et de ne taper la touche retour qu'a la fin. L'espace est un délimiteur, le retour en est un autre. Cette forme est dite implicite, il en existe d'autres que nous indiquerons au passage.
PULL : le fonctionnement de l'option PULL dépend du type de console utilisée. S'il s'agit d'une console de type CL1 ou Shell, le fonctionnement est limité. S'il s'agit d'une console de type Wshell ou Con.Man. le fonctionnement est normal, La différence entre les deux types de consoies est la capacité pour Wshell et Con.Man de gérer une pile.
- Fonctionnement simplifié avec CLI Shell
Cette instruction permet d'acquérir une chaîne de caractères, mais cette fois on peut choisir le moment de l'introduction de la chaîne. L'invocation se fera de façon plus simple : RX CompteLettres. Le programme invoqué sc déroule et au moment où la chaîne d'entrée est nécessaire, on trouve une
EXX LA VOIE ROYALE
I
forme semblable à celle-ci :
SAY "Tapez 2 nets séparés par un espace" ; lit l'opérateur
PARS3 UPPER PULL 'traitenent' ; ou
FULL 'traitenent' ; forme abrégée.
Et le programme attend une entrée suivie d'un retour charriot. Là encore,
c'est la partie ‘traitement' qui triera la chaîne acquise.
- Fonctionnement nonnal avec console Wshell ConMan Ces consoles incorporent un raffinement supplémentaire sous forme d'une pile. Une pile est une forme de mémoire atypée dans laquelle on peut mettre à peu près ce que l'on veut. On peut imaginer cette mémoire sous forme d'un tuyau dont une extrémité est dédiée à la sortie par construction. Il existe deux laçons d'empiler quelque chose dans ce tuyau. La première consiste à empiler par l'extrémité libre, si bien que par la sonie on verra arriver les éléments mémorisés dans l'ordre de mémorisation (en anglais First IN First Out. Premier entré premier sorti). Cette opération d'empilage est réalisée par une commande Arex.x QUEUE.
La deuxième façon consiste à pousser la pile vers le haut en mémorisant un élément par l'extrémité sortie. Dans ce cas. Il s'agit d'une pile Last In First Out. Dernier entré premier sorti. La commande Arexx qui réalise cette fonction est PUSH (ces deux commandes ne sont efficaces que s’il y a possibilité de pile dans la console).
Pour extraire quelque chose de la pile, il n’y a qu'un chemin : l'extrémité sortie. L'instruction Arexx qui permet d'extraire un élément de la pile est PULL. L'élément extrait est ôté de la pile et celle-ci descend d'un cran. Les deux modes de chargement sont simultanément possibles, et la responsabilité de la gestion incombe au programmeur.
Le fonctionnement de l'instruction PARSE UPPER PULL 'traitement’ devient alors plus clair. Si la console ne gère pas de pile, le programme attend une entrée clavier suivie d’un retour. Si la console gère une pile et que celle-ci contient quelque chose, il y a extraction réelle de la pile.
Deux cas peuvent encore se présenter. Que se passe-t-il à la suite d’un appel par PULL si la pile est vide ? La réponse est la même que pour une console sans pile, le programme attend une entrée clavier suivie d'un retour.
Que se passe-t-il si. à la fin du programme, il reste encore quelque chose dans la pile ? La réponse doit être circonstanciée. Cela dépend en effet de qui reprend la main. Mais dans tous les cas. Ce qui se présente à la sortie de la pile sera interprété, selon les règles de ce qui prendra la main. Exemple : le programme Arexx se termine et il y a retour à la console. Imaginons qu'il restait la chaîne "dir DHOdans la pile. A la fin de l’exécution du programme Arexx. Dès le retour à la console, il y aura exécution de l’instruction AmigaDOS "DIR DHO:". Pour généraliser, si ce qui reste dans la pile n'a pas de sens pour celui qui prend la main, il y a dans le meilleur des cas apparition d'un message d'erreur, ou. Dans le pire des cas. Du Guru.
Décrit sur MaVariable. Là encore et comme partout ailleurs, le mot UPPER peut être placé, s'il y a besoin, juste derrière PARSE.
IL reste maintenant à voir les formes dédiées de l'instruction PARSE. Ces formes sont dites dédiées parce qu’elles fournissent une information identifiée à priori sur l'environnement.
NUMERIC : cette option fournit une information en rapport avec les précisions numériques et les formats des nombres en usage. Elle fournit une chaîne de trois mots :
- DIG TS. Qui contient le nombre de chiffres de la précision des calculs ;
- FUZZ. Qui contient le nombre de chiffres à ignorer lors des opérations de comparaison numérique :
- FORM. Qui contient soit soit SCIENTIFIC soit ENGINEERING. Dans le premier cas. Les nombres sont présentés en notation exponentielle, ajustée de façon à ce que la partie non nulle de la mantisse soit comprise entre 0 et 1. Dans le deuxième cas. La forme est aussi exponentielle mais l'exposant varie de trois en trois (par mille) et la mantisse (si non nulle) est comprise entre 0 et 1000. Ces choix peuvent être effectués par ailleurs pour chaque opération réalisée dans le programme, au moyen de l’instruction NUMERIC (autre que l’option P.ARSE ici décrite) et de ses paramètres.
SOURCE : cette option retourne une chaîne qui contient six mots :
- COMMAND ou FONCTION indique si le programme a été invoqué comme une commande ou une fonction. Une des différences est que la commande retourne un code spécifique nommé RC (pour Retum Code), et qui a pour valeur 1 ou 0. Selon la réussite d'exécution de la commande (0 pour réussi 1 pour échec), alors que la fonction peut retourner une valeur ou une chaîne ;
- INDICATEUR BOOLEEN 0 1 indique que le demandeur attend une chaîne de caractères en retour ou non :
- CALLED indique le nom qui a été utilisé pour invoquer le programme :
- RESOLVED indique le nom qui a été utilisé en fin lors de l'appel réel ;
- EXT est l'extension du nom du fichier qui a été utilisée pour la recherche. La valeur par défaut est REXX. C'est pourquoi un programme intitulé Mon Programme. REXX peut être invoqué par MonProgramme tout simplement ;
- HOST indique l'adresse REXX de l'hôte qui a envoyé la commande.
VERSION : cette option retourne une chaîne contenant six mots :
- AREXX :
- VERSION contient la version de l’interpréteur courant. Ici par exemple,
1. 15.
- CPU indique un microprocesseur 68000 10 20 30 selon le cas :
- MPU contient NONE ou 68881. Ce qui indique l’éventuelle présence du co-processeur arithmétique ;
- VIDEO contient le standard vidéo courant, soit PAL pour les versions européennes ou NTSC pour les autres ;
- FREQ contient la fréquence du réseau : 50 Hz ou 60 Hz.
On peut commencer à envisager l'intérêt d'une console à pile pour échanger
des commandes et des paramètres entre des programmes de nature A RETENIR
différente.
Exi ERNAL : cette option ne fonctionne pas comme décrit dans le manuel. Elle a fait l'objet d'une rectification dans la version 1.15. Cette option attend systématiquement une entrée au clavier, non pas à partir de la console courante (qui gère les deux flux standards stdin et stdout) mais à partir du flux stderr de la console d'erreur, ouverte par appel de la commande TCO (Tracing Console Open). Placée dans le répertoire C:. TCO ouvre une fenêtre spéciale dans laquelle s'inscrit la trace de l'exécution du programme en cours et qui peut recevoir des entrées clavier. A partir de cette fenêtre, le fonctionnement de EXTERNAL est identique à celui de PULL, mais l'information ne provient pas de la pile. Ceci est fait pour éviter de perturber la pile qui a le statut de Public et peut donc servir à d’autres programmes. La fermeture de la fenêtre s’effectue par la commande TCC (Tracing Console Close), elle aussi placée dans C:. La fermeture peut toutefois ne pas être immédiate, à cause du double emploi de cette fenêtre.
VAR : mise pour "variable", cette option ne "regarde" plus vers l’extérieur mais fournit à une variable interne du programme, le moyen d'être traitée de la même façon par la partie 'traitement' de l'instruction PARSE. Par exemple, si MaVariable= 'chaîne de plusieurs groupes de caractères', 1 'instruction PARSE VAR MaVariable 'traitenent' effectuera le traitement
Selon que l'on utilise une console avec pile ou sans, certaines options de l'instruction PARSE fonctionnent différemment.
Les options SOURCE et les modes 'traitement' sont indépendants et pourront être combinés.
Dans les options SOURCE, il y a des options anonymes qui peuvent être utilisées selon le gré du programmeur et des options dédiées qui fournissent des renseignements sur l’environnement.
Les options SOURCE permettent de dialoguer avec l'intérieur du programme (VAR) ou avec l'extérieur de type Arexx (ARG) ou non (PULL)
Nous avons maintenant passé en revue toutes les options SOURCE de l'instruction PARSE. Nous analyserons prochainement la partie 'traitement’.
Pat
MOS CONNAIT LA
Ca fait maintenant deux mois que je vous en parle, le voici ! Quoi ? Mais le programme permettant de mélanger plusieurs musiques dans une seule banque 1
' Vérification de la validité des banques A$ =Input$ (l,20)
If Left$ (A$ ,4)o"Am3k" : Stcp : End If If Right$ (A$ ,8)o"Music " : Stcp : and If A$ =Input$ (2,20)
If Left$ (A$ ,4) >"ArBk" : Stcp : End If If Right$ ( A$ , 8 ) > "Music " : Stcp : End If
Rsn 3 espaces après Music Rem 3 espaces après Music
' Réservation de la banque de travail Lml=Lof(1)
IM2=Lof(2)
Reserve As Chip Data 3,LKl+LM2+256 ABANK=Start(3)+20
' Charge les entetes APOKE=ABANK HEADl$ =Input$ (1,16) KEAD2$ =Inout$ (2,16)
Comme vous avez pu le lire le mois dernier, les banques de musiques sont conçues pour contenir plusieurs musiques exploitant le même jeu d'instruments, ce qui est très avantageux en place mémoire.'Hélas, il manquait jusqu'à maintenant un utilitaire permettant de rassembler deux banques en une seule. Le programme que je vous propose fait ce travail : choisissez les noms des deux oanques à mélanser. Le programme procède à l'exploration des instruments des deux banques à la recherche d'instruments identiques, puis recopie les instruments nécessaires uniquement, suivis des musiques à la suite 1 une de l'autre et des pattems. Modifie les étiquettes de changement d'instruments et finalement, sauvegarde la nouvelle banque. Son travail terminé, il affiche le nombre d'instruments semblables ainsi que la place mémoire gagnée par rapport à la somme des tailles des deux banques.
' Addresses des différentes parties AXNSTl=Leek(Varptr(HEAD1S))+20 AINST2=Leek(Varptr(HEAD2$ ))+2 0 AMOSl=Leek(Varptr(HEAD1$ )+4)+20 AMDS2=Leek(Varptr(HEAD2$ )+4)+2 0 APATl=Leek(Varptr(HEAD1S)+8)+20 APAT2 =Leek(Varptr(HEAD2 $ )+8)+2 0 EPATl=Leék (Varptr (HEAD1$ )+12)+2 0 : EPAT2=Leek (Varptr(HEAD2$ )+12)+20 :
EPATl=Iof(l) : End If EPAT2=Lof(2) : End If
If EPAT1=20 If EPAT2=20
' Va faire le travail
Print At(0,10);"Je mélange ";F1$ ;" avec ";F2$
Print
Print "Ncmbre total d'instruments:";
Gosub MERGE_SAMPLES Print NTI;
If NTI NI1+NI2
Print " - Economie de";NIl+Nl2-OTI;" instrument(s)!’ End If Print
Le prostramme travaille le plus possible sur disquette : il est parfaitement utilisable avec 512 Ko de mémoire. De plus, il est parfaitement possible de fabriquer des banques de plus de deux musiques, en ajoutant simplement les banques l'une après l'autre.
Print "Ncmbre total de musiques:"; MOMD=SPOKE : Gosub MERGE_MDSICS Print NMD
TOP 50
Print "Ncmbre total de pattems:"; Gosub MERGE_PATTERNS : EBANK=APOKE Print NPAT
Ce programme permet de mettre en évidence une facilité de l'AMOS passée sous silence jusqu'à maintenant : la possibilité de faire fonctionner une musique sans perturber la précédente...
APORE=MDMD : Gosub MERGE_MÜSICS
Close
Exemple et démonstration :
- fusionnez deux des musiques de la disquette AMOS_DATA. Disons Funkey.Abk et MusicAbk ;
- chargez la banque ainsi créée en mode direct ;
- démarrez la première musique avec mdsic i :
- attendez quelques secondes, puis démarrez la seconde musique avec mdsic 2 ;
- arrêtez la seconde musique avec mdsic stop.
L3ANK=EBANK-ABANK+8 E=LM1+IM2-LBANK If E>0
Print : Print "Economie de";E;" octets!" End If Print
Print "Pressez une touche..."
Wait Key
' Sauve la banque.. APOKE=ABANK-2 0 STRPOKE["AmBk"] BDOKE[3] : BDOKE[0] STRPOKE["Music "ï BLOKE[AINST-ABANK] BLOKE[AMDS-ABANK] 3L0KE[APAT-ABANK] BLOKE[EBANK-ABANK]
Surprise ! La première musique reprend exactement à l'endroit où elle s'était arrêtée. J'ai conçu ce système pour permettre d'avoir une musique de tond pendant le jeu (Music 1 ) tout en produisant des bruitages complexes, sous la forme de musiques SoundTracker. Jusqu'à trois musiques peuvent ainsi être démarrées en même temps.
BLOKE[S80000000+LBANK]
Rem 3 espaces après Music
Attention : mdsic stop arrête la musique courante, alors que mdsic off arrête :outes les musiques...
F$ =Fsel$ ("*.Abk","","Ncm de la banque à sauver...") If F$ >""
Bsave F$ ,ABANK-20 To EBANK End If
ET DAISY ?
La taille du programme ne laisse (heureusement) pas suffisamment de place pour Daisy. Personne se s'en plaindra. D'ailleurs, il faut qu’elle termine le compilateur. Le mois prochain j'essaierai de lui laisser deux ou trois lignes.
Erase 3
Loop
MERGE_SAMPLES:
c est promis !
' Copie les instruments de la première banque, en stockant les nems Pof(1)=AINST1 : A$ =InputS(l,2) : Nil=Deek(Varptr(A$ ))
Pof(2)=AINST2 : A$ =Input$ (2,2) : NI2=Deek(Varptr(A$ )) INSTl$ =Input$ (l,NTl*32)
INST2$ =Input$ (2,NI2*32)
MELANGEUR DS MUSIQUES: plusieurs musiques dans une banque
(C) 1991 F.Lionet A.N.T.
Set Buffer 16
Dira 12(256),SDMI(256),SDM2(256) Global APOKE,SPCKE
' pour instrument calcule la semne de cczxtrole des 512 1ers sanples
For N=0 To NI1-1
A=Varptr(INST1$ )+N*32
AI=Leek(A)+AINST1 : LI=Min(512,Deek(A+8)*2)
Pof(1)=AI : AS=Input$ (l,LI)
S=0 : SA=Varptr(A$ )
For L=0 To LI-1
Add S,Peek(SA+L)
Next
SDM1(N)=S
Next
For N=0 To NI2-1
A=Varptr(INST2$ )+N*32
AI=Leek(A)+AINST2 : LI=Min(512,Deek(A+8)*2)
Pof(2)=AI : A$ =Input$ (2,LI)
DO
Screen Open 0,640,200,2,Hires : Curs Off : Colour 1,$ FF4 Centre At(,0)+"»> Mélangeur de musiques « "
Erase 3
Fl$ =Fsel$ ("*.Abk","tfcm de la première banque.","CPTT peur terminer") If Fl$ ="" : Edit : Ead If
F2$ =Fsel$ ("*.Abk", "", "Nom de la deuxième banque.", "CPIT peur terminer") If F2$ ="" : Edit : End If Open In 1,F1$
Cpen In 2,F2$
MUSIQUE
?
S=0 : SA=Varptr (A$ )
For L=0 To LI-1
Add S,Peek(SA+L)
Next
SüK2(N)=S
Next
' Cccçte les instruments semblables NTI=NI1
For N2=0 To NI2-1
A2 =Varptr(INST2 $ )+N2 * 3 2 L2=Leek(A2+8)
FLAG=-1
For N1=0 To NI1-1
Al=Varptr(INST1$ )+N1*32 Ll=Leek(Al+8)
If L1=L2 and SüMl(Nl)=SGM2(N2)
I2(N2)=N1 FLAG=0 : Exit End If Next If FLAG
I2(N2)=NTI : Inc NTI End If Next
' Recopie les instruments AINST=ABANK+16 APOKE=AINST : BDOKE [NIT]
SVXDE=APOKE+NTI*32
SP0KE=SVIDE+4
For N=0 To NI1-1
AI=Varptr(INST1$ )+N*32
A1=SP0KE : Sl=AINSTl+Leek(AI) : Ll=Deek(AI+8)*2 A2=SP0KE+L1 : S2=AINSTl+Leek(AI+4> : L2=Deek(AI+10)*2 If L2 =4
A2=SVTDE : L2=4 End If
BLOKE [Al-AINST] : BLOKE [A2-AINST]
BDOKE[Ll 2] : BDOKE[L2 2]
For 0=0 To 16 Step 4
BLOKE[Leek(AI+12+0)]
Next
SCOPY[1,SI,Ll]
If A2oSVIDE
SCOPY[1,S2,L2]
End If Next
For N=0 To NI2-1 If 12(N)>=NI1
AI=Varptr(INST2S)+N*32
Al=SPOKE : S1=AINST2+Leek(AI) : Ll=Deek(AI+8)*2 A2=SP0KE+L1 : S2=AINST2+Leek(AI+4) : L2=Deek(AI+10)*2 If L2 =4
A2=SVTDE : L2=4 End If
BLOKE[Al-AINST] : BLOKE[A2-AINST]
BDOKE[Ll 2] : BDCKE[L2 2]
For 0=0 To 16 Step 4 3L0KE[Leek(AI+12+O)]
Next
SCOPY [2, SI, Ll]
If A2oSVIDE
SCOPY [2, S2, L2]
End If End If Next
INST1$ =”" : INST2$ =""
APOKE=SPOKE
Retum
KERGE_KOSICS:
I2ül=A?ATl-AMDSl : Pof(l)=AM0Sl Mdl$ =Iaput$ (l,IMül) : NMUl=Deek(Varptr (MOIS) )
I2-TJ2 =A?AT2-AXDS2 : Pof ( 2 ) =AKUS2 MD2$ =Input$ (2,mu2) : NMD2=Deek (Varptr (K02$ ) )
Nku=NJÎDl+N> 02 : AMOS=APOKE : BDOKE [NMD]
SPOKE=APOKE+NKU*4
' Recopie les musiques de la banque 1 For N=0 To NMÜl-1
BLOKE[SPOKE-AMÜS]
A=Varptr (KCT1$ ) : AM=Leek(A+N*4+2)
If N NMül-l
FN=Leek(A+N*4+6)
Sise
FM=LKül End If
Ccçy A+AM,A+FM TO SPOKE Add" SPOKE, FM-AM Next
' Recopie les musiques de la banque 2, en pointant les nouveaux pattems
For N=0 To NM02-1
BLOKE[SPOKE-AMOS]
A=varptr(M02$ ) : AM=Leek(a+n*4+2)
If N NHD2-1
FM=Leek(A+N*4+6)
El se
FM=LKü2 End If
Ccpy A+AM,A+FM To SPOKE ' Change les numéros de pattems For P=0 To 3
AP=SPOKE+Deek(SPOKE+P*2)
Do
B=Deek(AP)
Exit If Btst(15,B)
Doke AP,B+NPAT1 Add AP,2 Loop
Next
Add SPOKE, FM-AM
Next
KD1$ ="” : Mü2$ =""
AP0KE=SP0KE
Retum
MERGE_PATTERNS:
' Recopie les pattems
Pof(1)=APAT1 : A$ =Input$ (l,2) : NPATl=Deek(Varptr(A$ ))
Pof(2)=APAT2 : A$ =Input$ (2,2) : NPAT2=Deek(Varptr(A$ ))
NPAT=NPAT1+NPAT2 : APAT=APOKE : BDOKE[NPAT] : SP0KE=APAT+NPAT*8+2 PATl$ =Input$ (1,NPAT1*8) : SPATl=Pof(l)
PAT2$ =Input$ (2,N?AT2*8) : SPAT2=Pof(2)
' Recopie betement les pattems de la première banque For N=0 To NPAT1-1 For P=0 To 3
BDOKE[Deek(Varptr(PAT1$ )+N*8+P*2)+N?AT2*8]
Next
Next
LPAT1=EPAT1-S?AT1 SCOPY[1,SPAT1,LPAT1]
' Recopie les pattems de la deuxième de la meme maniéré...
For N=0 To NPAT2-1 For P=0 To 3
BDOKE[Deek(Varptr(PAT2$ )+N*8+P*2)+NPAT1*8+LPAT1]
Next
Next
LPAT2=EPAT2-SPAT2 SCOPY[2,SPAT2,LPAT2]
' Analyse les pattems de la deuxième banque panr charger les instruments.
' Etiquette SET_INST=$ 900 For N=0 To NPAT2-1 For P=0 To 3
AP=Deek(APAT+2+NPATl*8+N*8+P*2)+APAT Do
B=Deek(AP) : Add AP,2 Exit If 3=$ 8000 If Btst(15,B)=0 If Btst(14,B)
Add AP,2 End If Sise
If(B and $ 7F00)=$ 900 I=B and $ FF B=$ 8900+I2(I)
Doke AP-2,3 End If End If Loop
Next
Next
PAT1$ ="" : PAT2$ =""
APOKE=SPOKE Retum
Procédure STRPOKE[S$ ]
For P=1 To Len(S$ )
Poke APOKE,Asc(Mid$ (S$ ,P, 1))
Inc APOKE
Next End Proc
Procédure BDOKE[P]
Doke APOKE,P Add APOKE,2 End Proc
Procédure BLOKE[P]
Loke APOKE,P Add APOKE,4 End Proc
Procédure SCOPY[FILE,POS,LONG]
Pof(FILE)=POS : A=0 While A L0NG
L=1024 : If A+L>LONG : L=LONG-A : End If A$ =Input$ (FILE,L)
Copy Varptr(A$ ),Varptr(A$ )+L To SPOKE+A Add A,L Wend
Add SPOKE,LONG End Proc
par François Lionet
C= A.MIGA NF.WS-TECH
5
NL .MERO 24 JL IIVAOI T
C A L’ASS
De nombreux lecteurs se - et nous - posent la même question : ne disposant pas de compilateur C, comment profiter des merveilleux programmes de Frédéric Mazué, Stéphane Schreiber et autre Docteur Von Glupa ?
Quelqu'un d'un tant soit peu mercantile aurait certainement répondu : abonnez-vous à une formule avec disquette... Mais l'ANT. Comme à son habitude, va beaucoup plus loin que ça et vous propose carrément de vous prendre par la main, en décorticant pour vous une (la ?) Manière de s'y prendre. Et comme un exemple concrêt est toujours plus parlant que de longs discours, j'ai choisi d'illustrer mon propos avec un très vieux programme paru dans l'ANT numéro.... 6 (Commodore Revue numéro 17) : le "sectorisateur" de la société Loriciel.
SECTORISATEUR ?
Un rapide rappel sur le but et l'utilité de ce programme : présenté dans l'ancienne rubrique ViewPort. Dans laquelle des éditeurs livraient leurs astuces de programmation, et programmé par Jean-Pierre Vitulli. Sectorise permettait d'écrire sur une suite de secteurs de la disquette placée en DFO:. Par le biais du trackdisk.device, un fichier AmigaDOS quelconque (image, musique, programme exécutable...).
PREPARATIFS
De quoi a-t-on besoin pour "transformer" un programme C en son équivalent assembleur ? Tout simplement d'un bon assembleur. J'entends par là "macro-assembleur", c’est-à-dire capable de jongler avec des fichiers includes et. éventuellement, de produire un code linkable plutôt qu’exécutable. Comme vous devriez maintenant en avoir l'habitude, c'est le Devpac II qui a été choisi, mais l’assembleur du Lattice, le DP a68k ou même l'ancêtre Metacomco feront l'affaire. Un peu de documentation ne fera pas de mal non plus et pour une fois, la Bible de l'Amiga (deuxième édition, celle à la couverture bleue) conviendra parfaitement. Mes précédents articles dans l'ANT (utiliser amiga.lib, mélange C assembleur) ne seront non plus pas de trop. Quelques connaissances, même rudimentaires, du langage C seront également les bienvenues.
PROBLEMES
A quel type de problème se heurte-t-on dans ce cas-là ? Le plus gros concerne les structures du C. intensivements utilisées sur l'Amiga. En effet, alors que le compilateur C sait d'office la taille des champs des structures, l’assembleur ne la connaît absolument pas. Et qui plus est. Ne se plaindra pas le moins du monde si vous référencez un mot long alors que le champ est de la taille d’un octet. D'où futilité de la documentation dont il est question dans le paragraphe précédent.
Un autre problème concerne les paramètres des programmes ; alors que la startup des programmes écrits en C contient une routine qui décompose la ligne de commande du CLI pour remplir le tableau argv et donner sa valeur correcte à argc. Rien de tel n'existe en assembleur. De même, le C dispose d'une bibliothèque de fonctions de base (printf, str..., fprintf, etc.) dont l’assembleur ne dispose pas. Une première solution consiste donc à ré-écrire de telles routines en assembleur : on obtient ainsi un code plus compact, répondant parfaitement à nos besoins, mais au prix d'un travail supplémentaire fastidieux. Une seconde solution, par ailleurs celle que j'ai retenue ici, consiste à linker le startup et la bibliothèque C avec le programme assembleur principal. Enfin, une troisième possibilité, celle que j'utilise le plus souvent par fainéantise consiste à se débrouiller comme on peut pour les obtenir à un moments ou à un autre.
Enfin, dernière difficulté, le choix des variables locales et des variables globales. Là. Tout dépend de l'importance de ces variables. Par exemple, un pointeur sur une zone de mémoire allouée devra être conservé, histoire de rendre cette mémoire au système en fin de programme. Par contre, si cette allocation a lieu dans un sous-programme et que la libération correspondante survient à la fin de ce même sous-programme, on aura tout avantage à conserver ce pointer dans un registre An. Voire sur la pile dans le pire des cas. Dans le même ordre d'idées, un compteur de boucle for() sera avantageusement placé dans un registre Dn. Même s'il a été déclaré global dans le programme C.
POINTEURS ET TABLEAUX
Le C est un langage orienté "pointeurs". Cela signifie qu'il offre tout un tas de facilités pour leur gestion (déclaration, changement de type (casting), arithmétique, etc.). En assembleur, un pointeur est une adresse 32 bits, un point c'est tout. Considérez l'exemple suivant, par ailleurs totalement inutile:
* Cette fonction retourne un pointeur sur le quatrième élément d'un tableau de mots, suivant le 1er élément égal à -1 *
DvfORD *fcrnction_quelconque (OMDRD *tai>leau_de_nots )

OVORD *toto; * toto pointe un tableau de mots (16 bits) *
toto = tableau_de_mots; * initialise toto *
while (*(toto++) != -1); * saute les mots > -1 *
* toto pointe maintenant le 1er élément APRES celui égal à -1 *
return(toto + 3); * saute 3 éléments et fin *
Transcrire une telle fonction en assembleur ne posera pas de problème particulier, pour peu que l'on se rappelle que toto pointe un tableau de mots de 16 biLs. Et qu'en tant que tel. Le compilateur C fincrémente de 2 octets lorsqu'il rencontre l'instruction toto-f-r. Et de 6 octets lorsqu'il rencontre toto + 3. Le code assembleur de cette même fonction ressemblera donc à quelque chose du genre :
fonction_quelconque:
movea.l aO,al ; al pointe le tableau de mots moveq -l,dO ; valeur de cemparaison . Loop cmp.w (al)+,dO ; compare un MIT et inc rémente al bne.s .loop ; boucle tant que différent addq.l 3*2,al ; saute 3 autres éléments move.l al,dO ; valeur de retour dans dO rts
Si la comparaison post-incrémentée se charge pour nous de maintenir al aligné sur des mors, l'addition finale devra prendre ce fait en compte.
COMPLEXITE
Comme tout langage évolué qui se respecte, le C permet d'écrire en une seule ligne de programme plusieurs opérations, que le compilateur se chargera de décortiquer en une suite d'instructions assembleur cohérente, suivant la priorité des différents opérateurs utilisés, l'utilisation ou non de parenthèses, etc. Par exemple, la ligne suivante, que l'on recontre très souvent dans des programmes en C sur l'Amiga :
if (GfxBase=(struct GfxBase *) OpenLibrary (GFXNSME,33L)) == NüLL) CleanRxit("Pas de graphies.libraxy");
L'ordre des opérations est le suivant :
- initialiser al et dO pour l'appel à OpenLibrary
- appeler OpenLibrary
- sauver le résultat dans la variable GfxBase
- si ce résultat est nul. Aller à CleanExit
- sinon, continuer le programme
'Ca. C’était un cas facile. Considérez maintenant l'instruction :
lvhIyX'X‘I'X‘X*X'Xl'X'X'X‘X,X'X*XvXvXBX'X*XvX*XvX'X'X“X"X’X‘X"X'Xv
BLEUR
sauve argc argv
C'est ici que
“* if ( (buffer=AllocMem(BÜFSIZE,MEMF_CHIP |MEMF_CLEAR) ==NULL) “* printf("Impossible d'alouer le buffer"n);
* **
XREP _CreatePort,_DeletePort
XREF _CreateStdIO,_DeleteStdIO
on a trouvé le ncm du fichier
,- alors on le passe
et on saute les espaces
MyVolume= ( char * ) BADDR ( ( ( struct DeviceList *)
BADDR(MyLock-> fl_Volume))->dl_Name);
Déjà moins évident, non ? La suite des opérations est la suivante :
- prendre le pointeur fl_Volume dans la structure MyLock
- le convertir du BCPL au C
- y puiser le pointeur dl_Name
- le convertir du BCPL au C
Et encore, ce ne sont pas là les cas les plus hardus. 11 faudra apporter une attention toute particulière aux boucles du genre for() et vhile(). Dont la condition d'arrêt peut souvent inclure un ou plusieurs appels à un ou des sous-programmes.
TREVE DE BAVARDAGES
Pour faciliter un peu les choses, j'ai inclus en commentaire du source assembleur, les lignes de source C telles qu'elles apparaissaient dans le listing original. A vous d'en faire bon usage.
* Sectorise. *
* Version assembleur du programme *
* de JP. Vitulli paru dans CR 17. *
* Démonstration de "traduction" *
* C => ASM. Le programme original *
* est écrit dans les commentaires *
* commençant par n“*n *
* **********************************
* Evidemment, c'est pas mal cpti- *
* misable (je me suis contenté de *
* traduire bêtement le programme) *
* **********************************
incdir ”include:n include "exec memory.i" inc lude "exec io.i" include " libraries dos. I" include "devices trackdisk.i"
include "exec exec_lib.i" include "libraries dos_lib.i"
BUFSIZE EQU 1000 ; Taille du buffer
DEFSTR MACRO ; cette macro définit une chaine de
dc. b .2-.1 ; caractère à la manière BCPL,
.1 cc.b 1,10 ; en plaçant d'abord sa longueur
.2 even ; puis la chaine elle-même. C'est
SŒM ; très pratique pour Write()
; Ce qu'on importe ; Ce qu'on exporte
0?T 0+,0W-,L+ ; code linkable et optimisé
XDEF _SysBase,_DOSBase
}
move.l SUFSIZE,dO
move.l MEMF_CHIP|MEMF_CLEAR,dl
CALLEXEC AllocKem
move.l d0,buffer(a5)
bne.s OkBuff
lea Errl(pc),aO bsr Puts bra end_prog
“* if (argc != 3)
“* printf("Usage : Sectorise fichier> secteur>"); end_prog();
... }
OkBuff movem.l args(a5) ,d0 a0 ; carme on ne connaît pas subq.l l,d0 ; le nctnbre d'arguments, on est
bne. S OkArgs ; obligé de ruser !
Lea Err2(pc),a0 bsr Puts bra end_prog
OkArgs clr.b 0(a0,d0.w) moveq 0, dO moveq 0,dl
lea dosname(pc) ,al ; la startup du C ouvre la moveq 0,d0 ; dos.library. A moins de linker
CALLEXEC OpenLibrary ; on doit le faire nous-même move.l dO,_DOSBase hne. S OkDOS
moveq S0,d0 rts
OkDOS CALLDOS Xnput ; la startup du C s'occupe aussi move.l d0,stdin(a5) ; de rechercher ces deux canaux CalldOS Output ; d'E S standards... move.1 dO, stdout( a5 )
.ArgLpl move.b (a0)+,d2 beq.s .ArgEnd cnpi.b " ",d2 beq.s .ArgLpl subq.l l,a0 move.l aO,filenam(a5)
.ArgLp2 move.b (a0) + ,d2 beq.s .ArgEnd cnpi.b " ",d2 bne.s .Arglp2 clr.b -l(a0)
.ArgLp3 move.b (a0)+,d2 crrpi.b " ",d2 beq.s .Arglp3 subq.l l,a0
movem.l d0 a0,args(a5) , moveq RSTORN_FAXL(d7
vraiment le programme c
saute les espaces
end_prog();
mêmes variables que le programme C 2 ; arguments du CLI
récupère le numéro du secteur
rsreset ; D'abord, les args rs.1 tdPort rs. 1 tdIO rs.1 buffer rs.l fichier rs.l numblks rs.w strtblk rs .w origine rs.w error rs.w
1 ; struct MsgPort ‘tdPort;
1 ; struct IOStdReq ‘tdReq;
1 ; char ‘buffer;
1 ; struct FileHandle ‘fichier;
1 ; nccnbre de blocs écrits
1 ; bloc de départ (int secteur_depart;)
1 ; bloc de fin
1 ; int error;
.ArgLp4 move.b (a0)+,d0
beq.s
.ArgEr-d ; de départ
cmpi.b
"0",d0
bcs.s
.ArgErr
cnpi .b
"9"+l,d0
bcc.s
.ArgErr
subi.b
“"0",d0
mulu
10,dl
ext.l
dO
add.l
d0,dl
bra. S
.ArgLp4
. ArgSrr moveq 0, dl
Puis quelques variables supplémentaires
fiieram rs.l filelen rs.1 stdin rs. 1 stdout rs.1 bavard rs.b VARSIZE rs .w
1
1
1
1
128
0
“* secteur_depart = atoi(argv[2]);
“* if (secteur_depart 011 secteur_depart > 1759)
“* printf("Secteur de départ %d invalide", secteur_depart). »** end_prog();
... }
Start lea VARS(pc) ,a5 ; a5 pointe les variables
ncm du fichier sa longueur
nécessaire pour printfO buffer pour printfO
.ArgEnd clr.w numblks(a5) move.w dl,origine(a5) move.w dl,strtblk(a5)
nombre de blocs = 0 bloc de fin (=départ) bloc de départ
SUITE PAGE 29
tmi.s
BlocErr
beq.s
WEND
cnpi.w
1759,dl
bis. 6
BlocOk
* *•
tdIO->io_Length = 512;
* **
tdIO->io_
_Data = buffer;
3locErr
lea
Srr3(pc),a0
* **
tdlO->io_Cctimand = CMD_WRITE;
lea
strtblk(a5),al
* **
tdIO->io_Offset = (long)(secteur_depart++ * 512);
bsr
Printf
* **
DoIO(tdlO);
bra
end_prog
movea.l
tdIO(a5),al
move.l
512, IO_LEÜJ3TH(al)
* **
if ((fichier=Open(argv[l],MODS_OLDFILE))==0)
move.l
buffer(a5),IO_DATA(al)
* **

printf("impossible d'ouvrir le fichier %s".
Move.w
cmd_write, io_cckmand ( ai )
argv[l] )
move.w
strtblk(a5),d0
* **
end_prog();
ext.l
dO
* **
}
addq.l
l,d0
BlocOk
move.l
filenam(a5),dl
moveq
9,dl
move.l
MODE_OLDFILE,d2
lsl.l
dl,d0
CALLDOS
Open
CALLEXEC
DoIO
move.l
dO,fichier(a5)
bme.s
OkFich
* **
if ( secteur_depart > 1759)
* **

printf("Dépassement du secteur 1759");
lea
Err4(pc),a0
* **
printf("Plus de place sur la disquette");
lea
filenam(a5),al
• **
break;
bsr
Printf
* **
bra
end_prog
addq.w
l,strtblk(a5)
cmpi .w
1759,strtblk(a5)
* **
tdPort=CreatePort(0,0)
bis. S
WHILE
OkFich
pea
$ 0.w
pea
$ 0.w
lea
Err7.1(pc),a0
jsr
_CreatePort ; dans amiga.lib
bsr
Puts
addq.l
8, sp
lea
Err7.2(pc),aO
move.l
dO,tdPort(a5)
bsr
Puts
bra. S
end_prog
* **
tdIO=CreateStdIO tdPort)
move.l
dO,-(sp)
* **
printf("Premier secteur : %d", secteur_depart);
jsr
_CreateStdIO ; dans amiga.lib
printf("Dernier secteur : %d", secteur_fin);
addq.l
4,sp
WEND
lea
Msg3.1(pc) ,a0
move.l
dO,tdIO(a5)
lea
origine(a5),al
bsr
Printf
* **
error = CpenDevice(TD_NAME,0,tdIO,0)
lea
Msg3.2(pc),a0
• **
if (error > 0)
lea
strtblk(a5),al
* **

printf("impossible d'ouvrir trackdisk.device">;
bsr
Printf
+ **
end_prog();
* **
}
* **
tdIO->io_
Ccnrvind-CMD UPDATE;
lea
tdname(pc),a0
* **
DolO(tdlO);
movea.l
d0,al
movea.l
tdIO(a5),al
moveq
0,d0
move.w
CMD_U?DATE, IO_CCKMAND ( al )
noveq
0,dl
CALLEXEC
DoIO
CALLEXEC
CpenDevice
move.w
dO, error(a5)
error = tdIO->io_Error;
bis. S
TDOk
movea.l
tdIO(a5),al
move.b
IO_ERROR(al), dO
lea
Err5(pc) ,a0
ext.w
dO
bsr
Puts
move.w
d0,error(a5)
bra
end_prog
* **
tdIO->io_
Length=0;
• **
tdXO->io_Coctrand=TD_PSOTSTA1US ;
* **
tdIO- > io_Ccmiiand=ETD_ï®TOR ;
* **
DoIO(tdlO);
* **
DoIO(tdlO);
TDOk
movea.l
tdlO(a5),al
clr.l
IO_LSNGTH(al)
move.w
TD_PROTSTATUS, IO_CCMMAND ( al )
move.w
ETD_MOTOR,IO_CCMKAND(al)
CALLEXEC
DoIO
CALLEXEC
DoIO
* **
if (tdIO->io_Actual != 0)
* **
if (error > 19)

printf("Disque protégé en écriture");
printf ( "Erreur trackdisk, code %â", error)
* **
end_prog();
cnpi.w
19,error(a5)
* **
}
bis. S
ErrOk
movea.l
tdIO(a5),al
tst.l
IO_ACTQAL ( al )
lea
Err8(pc),a0
beq.s
OkStat
lea
error(a5),al
bsr. S
Printf
lea
Err6(pc) ,a0
bsr
Puts
* **
end_prog();
bra
end_prog
end_prog:
* **
if (fichier) Close(fichier);
* **
priatf ("Placer la disquette destination dans D?0:");
ErrOk
move.1
fichier(a5) ,dl
* **
printf("puis taper retura");
beq.s
.endl
OkStat
lea
Msgl(pc),a0
CALLDOS
Close
bsr
Puts
lea
Msg2(pc),a0
* **
if (buffer) FreeMem(buffer,3DFSIZE);
bsr
Puts
.endl
move.l
buffer(a5),d0
beq.s
. End2
• **
getcharQ
;
lea
(3UFSIZE).w,al
bsr
getchar
exg
al,d0
CALLEXEC
FreeMem
* **
while(Read(fichier,buffer,512))
KHILE
move.l
fichier(a5),dl
* **
if (tdPort) DeletePort(tdPort);
move.l
buffer(a5),d2
.end2
move.l
tdPort(a5),d0
move.l
512,d3
beq.s
.end3
CALLDOS
Read
move.l
dO,-(sp)
tst.l
dO
jsr
_DeletePort ; dans amiga.lib
DISKS CHOUETTES
STEP. Deux instructions du micro-processeur sont donc nécessaires.
10
Fa
mi
Le Complex Interface Adapter, CIA pour les intimes, n’est pas seulement un super-chronomètre, comme certains auraient pu le penser suite à notre article du mois dernier. C’est également par lui que le système contrôle les quafre lecteurs de disquettes connectables à l’Amiga.
Note 4 : l'impulsion STEP doit toujours être rapide : inactif, actif, inactif. Les drives Amiga se déplacent d'une piste à l'autre en un maximum de 3 millisecondes. D'autres drives peut être plus rapide, d'autres encore plus lents. Lors d'un changement de direction, un minimum de 18 millisecondes est nécessaire entre les deux impulsions STEP.
ATTENTION : messieurs les demo-makers, soyez sympas. Pensez à ceux qui ont un tout petit peu gonflé leur Amiga ! Avec ma 68020 de compétition, les 3 4 des démos en track-loading refusent de tourner sur mon ordinateur, simplement parce que les délais logiciels (décrémentation d'un compteur) s'exécutent plus rapidement ! Vous avez 4 timers à votre disposition dans les CIAs. Utilisez-en au moins 1 pour régler les différents délais nécessaires à la mécannique... D'avance, merci.
Bien entendu, notre brave petit CIA ne fait pas tout ; il se contente d'assister le DMA disque, en démarrant le(s) moteur(s). En déplaçant la tête de lecture écriture, en choisissant la face active et en fournissant au système l'état de certaines broches, indispensable au bon fonctionnement du DOS. Ce qui n'est déjà pas si mal. Le DMA disque se charge quant à lui. Lorsque le drive est fin prêt, de la lecture ou de l'écriture des données. Il est capable de synchroniser la lecture avec un mot de contrôle, appelé SyncWord. Usuellement égal à S4489. Pour garantir l'alignement des données en mémoire. Le type de codage couramment utilisé est le MFM (comme sur IBM-PC ou Atari ST). Mais le contrôleur de disquette peut également lire des disquettes codées en GCR (comme sur l'ancêtre Apple II). Il paraît même qu'il serait capable de lire des disquettes 5" 1 4 Commodore 64. Mais je n'ai jamais eu l'occasion de vérifier !
PETITS EXEMPLES RAPIDES
Pour tous ces exemples, on considère qu'aô contient l'adresse de base du CIA-B. Et a4. Celle du CIA-A. Je vous conseille, pour des raisons de lisibilité, d'utiliser les labels définis dans "hardware cia.i" et de laisser Devpac supprimer pour vous les offsets inutiles (cf. Ciapra qui est égal à 0).
Include "hardware cia.i" lea $ bfd000,a5
a5 = CIA-B a4 = CIA-A
lea $ bfe001,a4
- démarrase du moteur de DFO:
ENCORE LES CIAS ?
Ce sont en fait les deux CIAs qui participent à cette tâche : 4 bits du pou A du CIA-A (adresse SbfeOOl, faut-il le rappeler ?) Servent d'indicateurs, tandis que carrément 8 bits du port B du CIA-B (adresse SbfdlOO) contrôlent les drives. Pour simplifier, le CIA-A est utilisé en entrée et le CIA-B en sortie.
Les tableaux donnés le mois dernier ne faisaient que rapidement état de ces bits ; les voici à nouveau, en plus détaillé pour le propos qui nous intéresse.
CIA-A, port A ($ bfe001). Utilisé en entrée.
Bit
Nom
5
RDY
4
TRACKO
3
WPRO
2
CHNG
CIA-B,
port B ($
Bit
Nom
7
MTR
6
SEL3
5
SEL2
4
SEL1
3
SEL0
2
SIDE
1
DIR
0
STEP
Fonction
Disk Ready. Ce bit passe à 0 quand le moteur du drive sélectionné tourne à sa pleine vitesse.
Track Zéro Detect. Ce bit passe à 0 quand la tête de lecture écriture est positionnée sur la piste 0. Write Protected. Ce bit passe à 0 si la disquette présente dans le drive est protégée en écriture. Disk Change. Ce bit passe à 0 quand on retire la disquette du drive. Il ne re-passe à 1 que lorsque qu'une disquette est à nouveau insérée et qu'une impulsion STEP a été transmise.
Port B ($ bfdl00). Utilisé en sortie.
Fonction
Disk Motor Control. Voir note 1.
Sélectionne le drive 3 (DF3:) si présent
Sélectionne le drive 2 (DF2:) si présent
Sélectionne le drive 1 (DF1:) si présent
Sélectionne le drive 0 (DFO:) TOUJOURS présent .
Sélectionne la face. Voir note 2.
Sélectionne la direction de déplacement de la tête. Voir note 3.
Envoie une impulsion de déplacement à la tête. Voir note 4.
Tous ces signaux, exceptés SIDE et DIR. Sont actifs à l'état bas (0).
Note ! : ce signal est un peu particulier ; il n'a pas d'action immédiate, mais n'est reçu par le drive que lorsque celui-ci est sélectionné par SEL3-SEL0. De fait, pour démarrer ou arrêter le moteur d'un lecteur donnée, il faut d'abord positionner MTR selon l'opération choisie PUIS sélectionner le drive en question.
Note 2 : SIDE doit être maintenu pendant 100 microsecondes avant une opération d'écriture, et pendant au moins 1.3 milliseconde entre une écriture et un changement de face. 0 sélectionne la face supérieure. 1 la face inférieure.
Note 3 : 0 sélectionne un déplacement vers le centre du disque (la piste 0 est située à l'extérieur du disque). Ce signal doit être mis AVANT l'impulsion
MotorOn:
DFO: off motor on DFO: on
bset CIAB_DSKSEL0,ciaprb(a5)
bclr CIAB_DSKMOTOR,ciaprb(a5)
bclr CIAB_DSKSEL0,ciaprb(a5)
rts ; le moteur tourne
- arrêt du moteur de DFO:
MotorOff:
DFO: off motor off DFO: on
bset CIAB_DSKSEL0,ciaprb(a5)
bset CIAB_DSKMOTOR,ciaprb(a5)
bclr CIAB_DSKSEL0,ciaprb(a5)
rts ; le moteur s'arrête
- recherche de la piste 0 du drive sélectionné :
CIAB_DSKDIREC,ciaprb(a5)
CIAB_DSKTRACK0,ciapra(a4)
.Ok
Step
Delay
.Seek
DIR=1
TrackO bset
.seek btst
beq. S bsr bsr bra. S .Ok rts
- avance la tête de lecture dans la direction indiquée par DIR :
Step bclr CIAB_DSKSTEP,ciaprb(a5)
bclr
nop
nop
nop
bset
rts
CIAB JDSKSTEP,ciaprb(a5)
- produit un délai suffisamment grand entre deux STEPs. Totalement en désaccord avec ce que j'ai dit plus haut, cette petite routine utilise un délai logiciel, alors qu'il faudrait programmer un Timer pour 3 millisecondes.
3000,d7 d7, *
Délai
move.w
dbra
; décompte et TestDrive
- teste si le drive sélectionné est prêt à lire ou à écrire :
TestDrive:
CIAB_DSKRDY,ciapra(a4) TestDrive
btst
bne.s
rts
La place étant limitée, vous retrouverez toutes ces routines, ainsi que d'autres, dans le programme d'exemple du prochain numéro. Nous en profiterons pour programmer un véritable délai totalement compatible, en utilisant nos connaissances sur les timers du CIA. Engrangées le mois dernier. D'ici là. Essayez de vous documenter sur le codage MFM. Vous verrez, c'est pas triste.
Loïc FAR
C= AMIGA NEW S-TF.CH fcl NUMERO 24 JUI AOUT
9
a ai *3 T r**?
I gj s n w
PLEINES
Après une interruption d’un mois dûe selon la formule consacrée à des problèmes techniques indépendants de notre volonté, voici la suite de notre petit tour au pays de la 3D en assembleur spécial démos.
Comme vous pourrez le constater dans les colonnes et les pages qui suivent, le programme que nous vous proposons est plutôt conséquent (ce sont pas loin de 800 lignes d'assembleur pur et dur que les abonnés sans disquette devront se taper...). Aussi, plutôt que de le passer en deux fois comme n'importe quel journal un tant soit peu civilisé l'aurait fait, nous avons pris le parti de publier dans un premier temps, le listing "nu", et dans un second temps (comprenez "dans le prochain numéro de TANT'), l'article et les explications de Jérôme Etienne.
Les plus perspicaces remarqueront que ce programme utilise encore certaines techniques mises en cause par Thomas Landspuig dans la rubrique Requester du mois dernier : assembleur auto-nxxlifié. Effaçage de l'écran par le couble blitter 68000. Calcul du point médian d'une droite selon une formule (dichotomie) jugée douteuse... Certes, mais comprenez que l'on ne puisse demander à un programmeur de changer ses habitudes comme ça. Du jour au lendemain. De plus, le but de cette rubrique étant avant tout théorique, ceux qui n'aiment pas la mise en pratique peuv ent toujours utiliser d'autres méthodes. Enfin, c'est la dernière fois que nous nous permettons des entorses à la philosophie de l'Amiga à laquelle tout le monde devrait adhérer, c'est promis-juré !
Inedir 'include:' include *hardware custan.i' include 'exec exec_lib.i'
; autres labels key = $ bfec01
custan = $ dff000
chip = $ 2
clear = $ 10000
plane_x =352 plane_y =285 bpl_depth = 2 bpl_width = plane_x 8 line_width = bpl_width*tpl_depth rroculo = bpl_width* (bpl_depth-l) bpl_size = bpl_width*plane_y page_size = line_width*plane_y
coplist_size = 40*4
* ***** macros allocmem: macro move.l l,d0; allocation de $ 1 octets move.l 2,dl ; type de ram sollicitée
move.l (_SysBase).w,a6 jsr _LVOAllocMem(a6)
move.l d0, 3 ; 3=adr de la mem recuperee beq 4 ; si erreur d'allocation => goto
4
endm
freemem: macro move.l l,al ; libérer 2 octet a partir move.l 2,d0 ; de l'adresse 1 move.l (_SysBase).w,a6
jsr _LTOFree!-fem(a6) ; mémoire a nouveau libre endm
wait bit: macro
btst 14,dmaconr(a5)
bne. S not_key_3
loop_wait_blt @:
subq.w 1,inc_ang_c+2
btst S14,dmaconr(a5)
rts
bne. S loop_wait_blt @
not_key_3:
endm
cmp.w $ 2f,d0 ; 6 tne.s not_key_6
* ************ main
prg *****************
clr.w inc_ang_c+2
bsr main_init
rts not_key_6:
main_loop:
cmp.w $ f,d0 ; 0
move.1 vposr( a5 ),
dO
tne.s not_key_0
and.l $ lff00,d0
add.w “10,coor_z_val-2
cmp.l $ f00,d0
rts
tne. S main_loop
not_key_0:
cmp.w $ 3c,d0 ; .
Bsr fill_obj
bne.s not_kev_point
bsr CŒrpute_sin_cos
sub.w 10,coor_z_valf2
bsr ccor_e_to_coor_p
rts
bsr move_obj
not_key_point:
bsr ccmpute_real_line_color
rts
bsr clr_obj
bsr draw_object
* ***** calcul les pians de lignes a tracer
bsr clip_screen
ccnpute_real_line_color: lea tab_face(pc) ,a0
move.b key,d0
teste le clavier
lea tab_line+4(pc),al
not dO
lea coor_p(pc),a2
ror.b l,d0
move.w (a0)+,d7
cnp.b $ 45,dO
ESC ?
Subq.w l,d7
beq init_end
loop_l ir.e_cclor_each_face :
bra main_loop
non => boucle
move.w (a0)+,d0
movm.w (a2,d0.w),dl d2 ; > cær ôj ptl (xl.yl)
* ***** effectue le flipping de page
move.w (a0)+,d0
clip_screen:
movem.w (a2,d0.w),d3 d4 : > cær pc2 (x2,y2)
move.1 plane_adr(pc),aO
move.w (a0)+,d0
move.1 tpl_log2_adr(pc),plane_adr
movm.w (a2,d0.w),c5 d6 ; > cœrbpü (x3,y3)
move. 1 tpl_log_adr ( pc ), tpl_log2_adr
sub.w dl,d3 ; d3= x2-xl
move.1 aO,bpl_log_adr
sub.w d2,d4 ; d4= y2-yl
* swap bitplanes dans la copperlist
sub.w dl,d5 ; d5= x3-xl
move.l coplist_adr(pc),a0
sub.w d2,d6 ; d6= y3-yl
moveq bpl_depth-l,d0
muls d3,d6 ; d6= (y3-yl) * (x2-xl)
move.l plane_adr(pc),dl
muls d4,d5 ; d5= (y2-vl) * (x3-xl)
add.l line_width,dl
sub.ld6,d5 ; d5= (y2-yl) (x3-xl)-(y3-yl) (x2-xl)
loop_modify_clistl:
bit.s hiden_face ; si d5 0 then goto
addq.l 2,a0
; si_face_cachee
swap dl
move.w (aO)+,dl
move.w dl,(a0)+
subq.w l,dl
swap dl
move.w (a0)+,d2
addq.l 2,a0
loop_line_color_each_line:
move.w dl,(a0)+
move.w (a0)+,d3
add.l bpl_width,dl
eor.w d2, (al,d3 .w)
dbf dO,loop_modify_clistl
dbf dl,loop_line_color_each_line
rts
dbf d7,loop_line_coior_each_face rts
* ***** Gère le clavier pour faire bouger l'ebjet
hiden_face:
move_obj:
move.w (a0)+,d0
move.b key,d0
add.w d0,d0
not dO
addq.w 2,d0
ror.b l,d0
lea (a0,d0.w),a0
and.w $ ff,d0
dbf d7,loop_line_color_eacb_face
cmp.w $ 3d,d0
7
rts
bne. S not_key_7
addq.w 1,inc_ang_a+2
* ***** trace les lignes de l'ebjet
rts
draw_obj ect:
not_key_7 :
lea tab_line(pc) ,al
cmp.w $ ld,d0
1
lea coor_p(pc),a2
tne.s not_key_l
move.w nb_line(pc),counc_line
subq.w l,inc_ang
_a+2
loop_each_face:
rts
locp_each_line:
not. Key_l :
move.w (al)+,d0
cmp.w $ 2d,d0
4
movm.w (2L2,d0.w) ,d0-dl
tne.s not_key_4
move.w (al)+,d2
clr.w inc_ang_a+2
movm.w (a2,d2.w) ,d2-d3
rts
tst.w (al)
not_key_4:
beq. S dont_draw_this_line
cmp.w $ 3e,d0
8
move.w (al),d7
tne.s not_key_8
clr.w (al)+
addq.w 1,inc_ang
_th-2
bsr draw_line
rts
subq.w l,count_line
not_key_8:
tne.s locp_each_line
cmp.w $ le,d0
2
rts
bne.s not_key_2
dont draw this line:
subq.w l,inc_ang
_b+2
addq.l 2,al
rts
subq.w 1,count_line
not_key_2:
bne.s loop_each_line
cmp.w $ 2e,d0
5
rts
bne.s not._key_5
clr.w inc_ang_b+2
count_face: ds.w 1
rts
count_line: ds.w 1
not_key_5:
crnip.w $ 3f,d0
9
bne.s not_key_9
* ***** en coordonnées planes
addq.w l,inc_ang
_C+2
coor_e_to_coorj? :
rts
lea coor_e(pc),aO
not_key_9:
lea coorjp(pc),ai
cmp.w $ lf,dO
3
move.w (a0)+,d7
subq.w l,d7 loop_coor_e_to_coor_p:
movem.w (a0)+,d0-d2 * d0-d2 = coor e
cos_c _val : move.w 0,d4 sin_c_val: move.w 0,d5 move.w d0,d3 move.w dl,d6 muls d5,d0 nuls d4, d6 sub.l d6,d0 add.l dO,dO swap dO muls d4,d3 muls 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 muls d5,d0 muls d4,d6 sub.l d6,d0 add.l dO,dO swap dO muls d3,d4 muls 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 muls d3,d4 muls d5,cL2 add.l d4,d2 add.l d2,d2 swap d2 coor_z_val:
add.w $ 3a0,d2 ext.l dO ext.l dl
moveq 9,d3 * détermine le point de fuite
asl.l d3,d0 asl.l d3,dl tst.w d2
beq.s no_zero_division divs d2,d0 divs d2,dl no_zero_division: add.w plane_x 2,dO add.w plane_y 2,dl
move.w dO, (al)+ * > dO-dl= coor p
move.w dl, (al) + *
dbra d7,loop_coor_e_to_coor _p
rts
* ***** trouve les cosinus et sinus
* ***** ccnpute_sin_cos: inc_ang_a: add.w 4,ang_a+2 inc_ang_b:
* des bons angles
add.w 4,ang_b+2 inc_ang_c:
add.w 4,ang_c+2 lea cos_tab(pc),aO move.w $ 100,do move.w $ 3fe,d7 ange : move.w 0,d3 and.w d7,d3 move.w (a0,d3.w),d4 add.w d6,d3 and.w d7,d3 move.w (a0,d3.w),d5 move.w d4,cos_c_val+2 move.w d5,sin_c_val+2 ang_b: move.w 0,d3 and.w d7,d3
; d3= angle * 2
; > d4 = cos(c)
; > d5 = sin(c) ;
; put cos in ram ; put sin in ram ; d3= angle *2
d4 = cos b
; > dS = sin b
;
mcve.w (a0,d3.w),d4 ; add.w d6,d3 and.w d7,d3 move.w (a0,d3.w),d5
move.w d4,cos_b_yal+2 move.w d5,sin_b_val+2 ang_a: move.w 0,d3 and.w d7,d3 move.w (a0,d3.w),d4 add.w d6,d3 and.w d7,d3 move.w (a0,d3.w),d5 move.w d4,cos_a_val+2 move.w d5,sin_a_val+2 rts
* ***** clipping en Y des lignes inter_y:
move.w d0,d4 *
add.w d2,d4 * > milieu x
asr.w l,d4 *
move.w dl,d5 *
add.w d3,d5 * > milieu y
asr.w l,d5 *
cnp.w d6,d5
tue.s inter_y_not_found rts
inter_y_not_found:
bit.S middle_inf_y* if roi.-Mle_y(d5) is greater move.w d4,d2 * > than d6
move.w d5,d3 * tben modify coord and locp
bra.s inter_y *
niidd1p_ir f 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
* ***** clipping en X des lignes inter_x: move.w d0,d4 * add.w d2,d4 * > milieu x
asr.w l,d4 *
move.w dl,d5 * add.w d3,d5 * > milieu y
asr.w l,d5 *
cnp.w d6,d4
fcme.s inter_x_not_found rts
inter_x_not_found: bit.S middle_inf_X* if middle_x( 34) 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 * tben modify coord and locp
xl: ds.w 2 x2: ds.w 2 save x: ds.w 1
* ***** dessine une ligne au blitter de ...... (do,Dl) à (D2-D3)
x_min = 0 x_max = plane_x-l y_min = 0 y_max = plane_y-2
draw_line:
cnp.w d3,dl * clipping de la droite
beq line_unvisible bit.s yl_less_y2 exg d0,d2 exg dl,d3 yl_less_y2:
movem.w d0-d3,xl cnp.w y_max,d3 ble.s no_inter_y_max cnp.w y_max,dl bgt line_unvisible move.w y_max,d6 bsr inter_y movem.w d4-d5,x2 movem.w xl (pc) ,d0-d3 no_inter_y_max: cnp.w y_min,dl bge.s no_inter_y_min cmp.w y_min,d3 ble line_unvisible moveq y_min,d6 bsr inter_y movem.w d4-d5,xl movem.w xl (pc) ,d0-d3 no_inter_y_min : cnp.w d2,d0 ble.s xl_less_x2 exg d0,d2 exg dl,d3
xl_less_x2:
movem.w d0-d3,xl cnp.w x_min,d0 bge.s no_inter_x_min cnp.w x_min,d2 ble line_unvisible moveq x_min,d6 bsr inter_x movem.w d4-d5,xl movem.w xl (pc) ,d0~d3 no_inter_x_mi.n : cnp.w x_max,d2 ble.s no_inter_x_max cnp.w x_max,d0 bgt line_vert inter_x_max:
put cos in ram put sin in ram d3= angle*2
d4= cos a
d5= sin a

put cos in ram put sin in ram
move.w x_max,d6 move.w d3,save_x bsr inter_x movem.w d4-d5,x2 move.w d5,dl move.w save_x(pc),d3 bsr line_vert movem.w xl (pc), d0-d3 no_inter_x_max:
* ** la ligne est visible line_visible: cnp.w d3,dl ble.s d3_sup_dl exg d0,d2 exg dl,d3 d3_sup_dl : addq.w l,dl sub.w dl,d3 sub.w d0,d2 tmi.s xneg cmp.w d3,d2 mi .s ygtx moveq %0011011,d5 bra.s lineagain ygtx: exg d2,d3
moveq %0000111,d5 bra.s lineagain xneg: neg.w d2 crp.w d3,d2 tmi.s xnygtx moveq %0011111,d5 bra. S lineagain xnygtx: exg d2,d3 moveq %0001111,d5 lineagain: add.w dl.dl add.w dl.dl
lea tab_line_adr(pc),a0
move.l (a0,dl.w),a0
add. 1 bpl_log_adr(pc),aO
ror.l 4,d0
add.w dO.dO
add.w d0,a0
swap dO
or.w $ b5a,d0
add.w d3,d3
add.w d3,d3
add.w d2,d2
move.w d2,dl
lsl.w 5,dl
add.w $ 42,dl
wait_blt
moveq -line_width,d6 move.w d6,bltanod(a5) move.w d6,bltdmod(a5) moveq -l,d6 move.l d6,bltaf>zn(a5) move.w d3,bltmod(a5) sub.w d2,d3 move .w d3, d4 tpi.s lineover or.w $ 40,d5 lineover: sub.w d2,d3
move.w d3,bltanod(a5) moveq tpl_depth-l,d3 locp_draw_line_each_tpl: lsr.w l,d7
bcc.s no_line_on_tbis_bpl wait_blt
move.w d5,bltconl(a5) move.w d0,bltcon0(a5) move.w d4,bltapt+2(a5) move.w $ 8000,bltadat(a5) move.l a0,bltcpt(a5) move.l a0,bltdpt(a5)
move.w dl,bltsize(a5) no_line_on_this_fcpl:
Xea fcpl_width(a0) ,a0 dbf d3,loop_draw_line_each_tç>l line_unvisible: rts
* ***** routine spéciale pour tracer des droites verticales line_vert: cmp.w d3,dl beq.s no_line_vert ble.s dl_inf_d3 exg dl,d3 dl_inf_d3: sub.w dl,d3 add.w dl.dl add.w dl,dl
lea tab_line_adr+4 (pc), aO move.l (aO,dl.w),aO lea fcpl_width-2(aO),aO add.l fcpl_log_adr(pc) ,a0 moveq line_width-2, d2 cmp.w 3,d7
hue.s line_vert_not_color_3 add.w d3,d3 moveq bpl_width-2,d2 bra.s draw_line_vert line_vert_not_color_3: cmp.w 2,d7 hme. S draw_line_vert lea hpl_width(aO) ,a0 draw_line_vert: lsl.w 6,d3 addq.w l,d3 wait_blt
moveq -l,dO * plus rapide que
move.l d0,bltafwn(a5) *'tnove.l -l,bltafwm(a5) ' move.w d2,bltcmod(a5) move.w d2,bltdmod(a5) clr.w bltconl(a5) move.w $ 35a,bltcon0(a5) move.w l,bltadat(a5) move.l a0,bltcpt(a5) move.l aO,bltdpt(a5) move.w d3,bltsize(a5) no_line_vert: rts
* ***** efface l'ecran avec
* ***** ie blitter et le 68000 clr_6bj:
* premier effacement au 68000 rrove. 1 sp, save_sp
novan.l arpty_buffer(pc),d0-a6 * met les
* registres
à 0
move.l bpl_log_adr(pc),a7 lea page_size(a7),a7 move.w 32,clr_68000_counter loop_clr_68000 : rept 10
movem.l d0-a6,-(sp) endr
subq.w l,clr_68000_counter bne.s locp_clr_68000
* effacement au blitter lea custcm, a5 wait_blt
move.1 hpl_log_adr(pc),bltdpt(a5) clr.w bltdmod(a5) move.l $ 1000000,bltcon0(a5) move.w 79*64+fcpl_width 2,bltsize(a5) move.l d0,a5
* second effacement au 68000 move.w 4,clr_68000_counter
locpl_clr_68000: rept 10
movem.l d0-a6, - (sp) endr
subq.w l,clr_68000_counter bne.s loopl_clr_68000 move.l d0,-(sp)
lea custcm, a5
move.l save_sp(pc),sp
rts
save_sp: ds. 1 1
clr_68000_counter: ds.l 1
empty_buffer: ds.l 15
* ***** rençlit la totalité des plans
* ***** en une seule fois fill_obj: move.1 tpl_log2_adr(pc),aO
add.l page_size-2,a0 wait_blt
moveq -l,d0 * > plus rapide qu'ion
move.ld0,bltafwn(a5) * 'anve-l -l,blta£w2(a5) '
clr.w bltcmod(a5)
clr.w bltdmod(a5)
move.l a0,bltcpt(a5)
move.l aO,bltdpt(a5)
move.w $ 03aa,bltcon0(a5)
move.w $ 0012,bltconl(a5)
move. W plane_y*hpl_depth* 64 +bpl_width
2,bltsize(a5)
orts
main_init:
move.l (_SysBase).w,a6 lea custcm, a5
allonnm page_size, chip+clear, tpl_log2_adr, fin alloorem page, size.chiotclear.bol lco adr.
Freemem_bpl_lcg2 alloorem page_size, chip+clear, plane_adr,
fxeemsm_bpl_log alloanem ccplist_size,chip,coplist_adr,
f reemem_plane
jsr _LVOForbid(a6)
move.w $ 03e0,dmacan(a5) ; ail dma off
except disk
* build tab_line_adr
lea tab_line_adr(pc),a0 move.w plane_y-l,d2 moveq 0,d0 locp_build_tab_line: move.w d0,dl mulu line_width,dl move.l dl,(a0) + addq.w l,d0
dbf d2, loop_build_tab_line
* initialise l'ecran
move.w (bpl_depth)«12+5200,hplcon0(a5)
clr.w fcplconl(a5)
clr.w bplcon2(a5)
move.w aodulo,bpllmod(a5)
move.w modulo,bpl2mod(a5)
move.l $ lb713 6dl,diwstrt(a5)
move.l $ 3000d8,ddfstrt (a5)
* cree la ccpper list move.l coplist_adr(pc),a0 moveq fcpl_depth-1, dO move.l plane_adr(pc),dl move.w bplpt,d2
locp_i.nit_clist : move.w d2,(a0)+ addq.w 2,d2 swap dl
move.w dl, (a0) + swap dl
move.w d2,(a0)+ addq.w 2,d2 move.w dl, (a0) + add.l bpl_widtb,dl dbf dO,loop_init_clist move.l $ fffffffe,(a0)+
* init frrvqp
lea cmap(pc),a0 lea color(a5), al moveq 2«fcç>l_depth-l,d0 locp_init_cmap:
move.w (a0)+,(al)+ dbf dO, loop_init_cmap
move.l ccplist_adr,copllc(a5) clr.w copjmpl(a5)
move.w $ 83c0,dmacon(a5); dma sprite,
ccpper & tpi
rts
cmap: de .w 0,$ ff,$ cc,$ aa
tab_line_adr : ds. 1 plane_y
* ****** init end init_end:
move.l (_SysBase).w,a6
lea gmame(pc) ,al ; nern de la library ds al
moveq 0,d0 ; versicn 0 (the last)
jsr _LVOOpenI,ihrary(a6) ; lib graphique
ouverte
move.l d0,al ; adr de graphiebase ds al
parj
move.l 38(al),copllc(a5); chargement de ; l'adr de l'old
clr.w copjnpl(a5)
jsr _LVOCloseLibrary(a6)
ccplist et lance- lib graphique fermée
move.w $ 83e0,dmacon(a5); canaux dma ; nécessaires jsr _LVOPemit(a6) ; mlti tasking autorise
freemem_coplist: freemem ccplist_adr (pc),
coplist_size freemam.plane: freemem plane_adr(pc),
page_size
freemem_tpl_log: freemem tpl_log_adr(pc),
page_size
freemem_hpl_log2 : freemem bpl_log2_adr (pc),
page_size
fin: moveq 0,d0 ; flag d'erreur desactive
rts
grname: dc.b "grapcics.library.O
evem
plane_adr: ds.l 1
bpl_log_adr: ds.l 1 tpl_log2_adr : ds. 1 1
coplist_adr: ds.l 1
tab: include 'cos_tab.s'
nb_point =
c = 200
les ce»;des points cens
i'eSydce.
- le m-ire àe points doit etre défini par *nb_poinf car je n'en sers plus haut
- la 1’ valeur de la liste est le axtre de peints puis la au=essicc des ecctfaaees (x,y,z)
ceci est le ixif fer ou sont arâcrisées les coordonnées après
la projecticc sur l'ecran
indique le lisses
- > chaque liçne est representee par
3 octets, les 2 premiers sent les numéros des peints a relier et le troisieœe est utilise par le proçrarme pour savoir sur quel
Ce peut facilement remarquer que les numéros des points sont tous ~.ês par 4, ceci par ne pas avoir à les multi plier au notent de l'accès à la coordonnée plane
te de faces de l'objet
coor_e:
de .w
nb_poiet*
dc. w
c,c,c
dc. w
c,-c,c •
dc. w
- c,-c,c •
dc. w
- c,c,c *
dc. w
c,c,-c *
dc. w
C. -C.-C *
dc. w
- c,-c,-c*
dc. w
- c.c.-c *
coor_p:
ds.l
nb_point*
nb_line

dc. w
12
tabline:
de. W
0,4,0 *
dc. w
4,8,0 *
dc. w
8,12,0 *
dc. w
12,0,0 *
dc. w
16,20,0 *
dc. w
20,24,0 •
dc. w
24,28,0 *
dc. w
28,16,0 •
dc. w
0,16,0 •
dc. w
4,20,0 *
dc. w
8,24,0 *
dc. w
12,28,0
tab_face :
dc. w
6
dc. w
24,20,4 •
dc. w
4
dc. w
1
dc. w
54,6,60,2
dc. w
0,16,28 •
dc. w
4
dc. w
1
dc. w
48,42,66,
dc. w
28,24,8 •
dc. w
4
dc. w
2
dc. w
60,12,66,
dc. w
20,16,0 •
dc. w
4
dc. w
2
de .w
48,24,54,
dc. w
16,20,24-
dc. w
4
dc. w
3
dc. w
24,30,36,
dc. w
8,4,0 *
dc. w
4
dc. w
3
dc. w
0, 6,12,1£
= les 3 points d'erientatico = le occire de côtés du polygone = la couleur du polygone D • = les lignes du polygone autre face ce renargue encore que les ismercc
, 18 * toujours peur les nênes raisons.
autre face
- les numéros des lignes sont eux par £ peur les rênes raisens c-a-d , 36 * peur avoir un accès pi’ig raçri de autre face
autre face
§
Notre concours lecteur nous entraîne ce mois-ci au pays des mathématiques. Franck Chatton et Alain Mignon proposent en effet un programme qui sort des sentiers battus : il calcule le nombre PI avec une précision pouvant atteindre 45 000 décimales !
La première tentative de calcul de PI vraiment raisonable. Après les pifométrages à base de fraction de l'antiquité (et d'après..., Lambert n'ayant prouvé l'irrationalité de Pi qu’en 1761), semble revenir à Leibniz qui utilise le développement en série de l'arctangente : sachant que Tan(Pi 4)=1, Pi 4= 1-1 3 +1 5-1(7 +1 9, Mais on a trouvé largement mieux depuis. Signalons que Schanks a calcule en 1 8 74 les 707 (ne rigolez pas. Il n'avait pas d'oninateur ! N'empêche qu'elles pourraient quand même être justes...) qui sont gravées daas une salle du palais de la découverte.
UN PEU DE MATHEMATIQUES
Nous n'allons surtout pas utiliser la formule de Leibniz qui est, en matière de convergence, encore plus un veau qu'une Harley, ni même celle d'Euler (Pi 4=Âtan( 1 2)+Atan( 1 3)) qui se traine encore passablement, mais celle de Machin : Pi 4=4Atan(l 5)-Atan(1 239). Pour calculer l'arctangente. Nous allons utiliser son développement en série entière, sachant que Atan(x)=SIGMA(-lpi (2i+l)*.P 2i+l). Enfin pour calculer les arctangentes. Nous n’allons pas calculer bêtement la somme telle que je viens de l'écrire, mais nous allons utiliser l'algorithme de Homer, i.e. pour calculer aXh2+bX+c. Nous ne calculons pas a*X*X+b*X+c, mais ((a)*X+b)*X+c. Ce qui est la manière la plus économique en nombre d'opérations donc en temps, d'évaluer un polynôme.
PETIT HISTORIQUE
Initialement, nous disposions d’un programme de calcul de PI (merci à Laurent Charbonnel de nous avoir fourni le source), qui bien qu'un peu lent (ah. Les subtilités de l'euphémisme : plus de 10 heures de calcul pour... 5000 décimales !), ridiculisait déjà notre polytechnicien de prof de maths prétentieux, avec son super logiciel "c'est môâââ qui l'ai fait" sur (âmes sensibles s'abstenir) XT en Turbo Pascal et qui pendant ce temps calculait poussivement ses 2000 décimales, et encore... Ce programme laissait une large place à l'optimisation, et la version actuelle n’a plus beaucoup (et même plus du tout) de points communs avec son ancêtre éloigné, hormis bien sûr la fonction.
UN PEU DE PRATIQUE
L'utilisation de la méthode de Homer nous oblige à calculer le rang jusqu'auquel nous devons pousser le développement de la série pour obtenir la précision requise avant de commencer le calcul. Le rang maximal à été calculé en tenant compte des erreurs diverses et vous garantit une précision de 1 E-p quand vous demandez p décimales.
"Oh l'autre eh, comment y va les stocker ses décimales, ça passe même pas en double précision !" Pensez-vous. Remarque éminemment pertinente au demeurant. Nous allons regrouper les décimales par groupes de 4 dans des mots, eux-mêmes situées dans des zones de mémoire que nous aurons allouées.
Attention, ce n'est pas du DCB. Mais alors pourquoi quatre et pas 5 ? Parce que 65535 10A5. Les heureux posseseurs de 68020 et plus pouront encore améliorer l'algo car les mots longs permettent de stocker 9 décimales, mais le 68000 ne peut malheureusement multiplier et diviser que des mots, d'ou la limitation à 45000 décimales de ce programme (il est possible de faire plus, mais il faut déjà environ 9 heures avec ce programme et il serait notablement
ralenti par cette nouvelle modification).
L'arctangente étant impaire et le signe des coefficient alterné, nous allons améliorer la méthode de Homer en n’écrivant pas ciX-bXA3+cXA5+...=X*(a+X*(0+X*(-b+X*(0+X*(c+...))))) mais
aX-bXA3+cXA5+...=X*(a-X2*(b-X2(c-...))))). avec X2=XA2 (étonnant non ?) Calculé une fois pour toutes au début. Ruse subtile : comme nous allons calculer deux arctagentes, pourquoi calculer deux fois les mêmes coefficients (NDLR : Keskidi ?) ? Une partie des coefficients l (2i+l) étant commune ai deux développements, leur calcul sera mené simultanément à partir d'un certain rang.
Attention, pour les possesseurs d'A500 sans horloge, le chronomètre ne fonctionnera pas. Mais il ne provoque cependant pas de plantage.
Enfin, le but initial de notre programme étant la performance pure, nous avons encore gratté un peu de temps de calcul au sytème à coups de Forbic et de Disable. Le tout assaisoné d'une supression bestiale de DMA d'écran qui piquait quelques cycles au 68000 en haute résolution, avec pour effe secondaire de fournir un blanker pour les distraits et un témoin d'éxécution di programme.
* Gary Copper Présente
* Copyright GCT 1990
* Calcul des décimales de pi
* PI =16 ATNU 5) - 4 ATN(l 239)
opt c+
* Attention: Démarrage à partir du CLI EXCLUSIVEMENT !!!!!!!
Incdir "include:“ include "exec exec_lib.i" include "libraries dos_lib.i"
Usage:
PI nb de décimales
Start move.b 0,-l(a0,d0) ;0 à la fin des paramètres
irovem.l dO aO,-(a7) ;empile aO & dO
;Qn va ouvrir la ;dos.library
lea DosName,al
moveq 0, dO
CALLEXEC OpenLibrary
move.l dO, DOSBase Pointeur dosbase dans dO
;Si d0=0 il y a erreur Récupération de aO & dO ,-Code d'erreur dans dO ;An revoir
bne. S DOS
movem.l (a7)+,dO aO moveq. 1 -l,d0 bra FIN
DOS CALLDOS Output .-Recherche la sortie courante
move.l dO,Stand_output;et la sauvegarde
* ****** Récupération de la
précision
movem.l (a7)+.dO aO
;On dépile aO & dO
subq
l d0
;d0=d0-l
beq
Erreurl
;pas de paramètres, donc erreur
moveq
0,dl
;dl = 0 (nb de décimales)
moveq
0,d2
,-d2 = 0 (caractère courant)
Loopl move.b
(a0)+,d2
;Charge 1 caractère dans d2
cmp.b
$ 20,d2
;Est-ce un espace ?
Beq.s
Loopl
;Oui, on le saute
move.l
dl,d3
; Multiplication par 10 de dl
lsl.l
3,dl
;= 3 décalages
add.l
d3,dl
;+ 2 additions
add.l
d3,dl
sub.b
48,d2
,-Transforme d2 en chiffre
cmp.w
9,d2
,-d2>9 ?
Bgt
Erreurl
Oui, sortie (message 1)
cmp. W
0,d2
,-d2 0
bit
Erreurl
Oui, Sortie (message 1)
add.l
d2,dl
dl=dl+d2
Bell cmp.b
0,(aO)
Fin ?
Bne.s
Loopl
Non, on boucle !
Erp. 1
45000,dl
dl>Ncmbre maxi de décimales ?
Bgt
Erreur2 ,-Oii sortie (Message 2)
dc. b
dc. b
Fmsgl
Msg2 !',$ a,0 Fmsg2
'modifié et adapté par ',$ 9b,'0 33 40m'
'Franck Chatton & Gary Copper',$ 9b,'Gn',$ a,$ a,0 even
dc. b 'Pas plus ce 45 000 décimales (pour le mxnent
* *** Réservation mémoire move.l dl.Nbdec
;Sauve le nb de décimales ;Augmente la précision
;2 chiffres par octet ;nb pair d'octets demandés ;Sauve dl ;d0=dl*3
addq lsr.l bclr move.l move.l lsl.l add.l move.l
CALLEXEC AllocMem
move.l
tne. S
move.l
bra
8,dl
l,dl
0,dl
dl,Taille
dl,dO
l,dO
dl,dO
Récupération de l'heure lea $ dc0000,al z Adresse horloge A500 2,d0 3 paramètres à récupérer
«15,dl ,- Masque
move.l (al)+,d2 Récupère 1 paramètre dl,d2 Masque les bits inutiles
«$ 30, 32 Transforme en code ASCII d2,-(a0) Range dans la chaîne
(al)+,d2 On passe à la seconde moitié
dl,d2 du paramètre
«$ 30,d2 que l'on range aussi dans
d2,-(a0) la chaîne
l,a0 z On saute le ':'
d0,H__bcl ; et on boucle
; fini !
Affichage de l'heure
Stand_output,dl Sortie standard dans dl H_msg,d2 ; Adresse de la chaîne
H_msgf-H_msg,d3 Taille de la chaîne Write
fin !
Heure
moveq
moveq
H_bcl
and.l
add.b
move.b
move.l
and.l
add.b
move.b
subq
dbf
rts
* ******
Aff_Heure:
move.l
move.l
move.l
CALLDOS
rts
H_msg
Départ
Arrivée
H_msgf
«$ 10001,dl
;CLEAR+P03LIC
dO,Pi ; Sauve l'adresse du nombre Pi
MemTerp ;Si d0>0 on continue $ 14,-(a7) ,-Erpile le message d'erreur
END ;Sort
MemTenp add.l Taille,dO ; Calcule l'adresse de Tenp
move.l dO.Tecp ;et la sauve
MemBis add.l Taille,dO move.l dO,Bis
Idem pour 3is
* ****** Noyau du programme Calcul move.l «Départ,aO bsr Heure
;a0 pointe sur l'adresse Départ ;où on sauve l'heure horloge
%100000000,$ dff096
,-Stcçpe la EHA bitplane
move.w
CALLEXEC Forbid ; Stoppe le Multitask
CALLEXEC Disable ; Stoppe les interruptions
bsr Calcul_pi ;Calcul et affichage de PI
CALLEXEC Enable .-Remet les interruptions
CALLEXEC Permit Remet le Multitask
dc. b
dc. b
dc. b
even
'Début du calcul: HH:MM:SS'
$ a,'Fin du calcul: HH:MM:SS'
$ a
%1000000100000000,$ dff096
Remet la EMA bitplane
move.w
move.l
bsr
bsr
Coeur du programme de calcul
Calcul_pi: move.l move.l move.l move.l lsr.l subq
bsr. S
bsr
bsr
bsr
bsr
rts
«Arrivée,aO Heure Aff Heure
zaO pointe sur Arrivée où on sauve l'heure On affiche l'heure
Temp.aO Bis,al Pi,a2 Taille,d2 «l,d2 «l,d2
pointeurs Tenp, Bis, Pi
et Taille 2 à demeure dans aO, al, a2 et d2 z d2=Taille 2-l
* ****** Restitution de la RAM Rendmem move.l 0,-(a7)
Eïrpile 0 (Pas d'erreur) Adresse de la RAM Taille de la ram=Taille*3
move.l move.1 lsl.l add.l CALLEXEC FreeMem bra.s END
Pi, al Taille,dO l,d0 Taille,dO
On rend la RAM Et on s'en va
Arctg évalue Arctg 1 5 & Arctg 1 239
Mulpi4 Arctg 1 5 * 4
Sub Arctg 1 5 - Arctg 1 239 -> PI
Mulpi4 PI = 4* PI
AffichePI Affichage
Sortie
Calcul des 2 Arctangentes
* ****** Ebreur 1: paramètres incorrects Erreurl move.l Stand_output,dl Sortie standard dans dl move.l «Msgl,d2 Adresse message dans d2
move.l EMsgl-Msgl,d3 Taille message dans d3
CALLDOS Write
move.l «$ lb,-(a7) On empile un code d'erreur
bra.s END Et on s'en va
* *****
Arctg239
Arctg:
move.l
lsl.l
addq
divu
move.l
mulu
swap
mulu
divu
and.l
add.l
move.1
lsl.l
addq
move.l
move.l
bsr
subq
1000, (aO) Tenp = 1 (Tenp est le nom de z la variable qui contient l 2n+l) On va calculer le rang n jusqu'où
Taille,d3
l,d3 l,d3 36223,d3 d3,d6 7615,d3 d6
7615,d6 36323,d6
$ ffff,d6
d6,d3
d3,d0
l,d0
l,d0
d0,dl
a0,a3
Div
l,d3
pousser le développement de l'Arctg en rusant pour ne pas calculer de : LOG et pouvoir évaluer n avec la formule n = nb dec*7615 36223 sans dépasser les limites de divu. On peut donc utiliser cette routine pour calculer plus de 45000 décimales, la limitation étant
imputable l'algo utilisé par DIV.
On efface le reste n est dans d3
On calcule maintenant 2*n*l.
Si 2*n+l > 65535 alors la routine DIV fait n'importe quoi 2n+l -> dl On divise Tenp grâce à Div n=n-l
* ****** Erreur2: trop de décimales Erreur2 move. 1 Stand_output, dl Idem Erreurl move.1 Msg2,d2
move.l FMsg2-Msg2,d3
CALLDOS Write move.l $ lb,-(a7)
END move.l (a7)+,dl move.l dl,dO CALLDOS Exit FIN rts
Dépile le code d'erreur
le place dans dO sort en douceur
Adieu !
* ****** Zone des données DosName dc.b 'dos.library',0 even
_DOSBase de. 1 0 Stand_output de. 1 0
Pi de.1 0
Tenp de. 1 0
Bis dc.l 0 Taille dc.l 0
Nbdec de.1 0
Msgl dc.b $ a, $ 9b,'3 33 40mDsage ',$ 9b,'OmPI «Précision»',$ a,$ a
dc. b $ 9b,'l 32 40mPl, par ',$ 9b,'0 33 40mGary copper '
dc. b $ 9b,'l 32 40md"après un algorithme',$ a,'original de '
dc. b $ 9b,'0 33 4OmLaurent Charbonnel',$ 9b,'l 32 40m"
dc. b ' (Hello to you frem GCT!)',$ a
* ** ArctgS move.l lsl.l addq divu move.l mulu swap mulu divu
Taille,d7 l,d7 l,d7 20087,d7 d7,d6 14369,d7 d6
14369,d6 20087,d6
Même routine que Arctg239
sauf que n= nb dec*14369 20087
and.l
$ ffff,d6
;On efface le
acd.l
d6,d7
; n dans d7
move.w
1000,
(a2)
; PI = 1
move.l
d7,d0
lsl.l
1
,d0
addq
l,d0
move.l
d0,dl
;2n+l dans dl
move.l
a2,a3
;On divise PI
bsr. S
Div
subq
l,d7
;n=n-l
* ** Développement
Pour gagner du temps, on calcule 1 seule fois l 2n+l et on travaille sur les 2 arctangentes en même tenps.
Dev subq move.1 moveq bsr. S bsr .s move.l bsr cmp.l dble move.l move.l bsr move.l bsr dbf
2,d0
a2,a3
25,dl
Div
Divl
a2,a4
Subteip
d3,d7
d7,Dev
a0,a3
57121,dl
Div
a0,a4
Subtemp
d7,Dev
Tenp fiant; a.3 On pointe sur la fin des 2 variables Taille (mots) dans d6 On efface x
Idem Sub
une fois que n2=nl, le calcul de Arctg 1 239 ccmnence.
* Remarque: Alors, le
* test cnp ... dble devient inutile et ralentit le prg. Pour un
* maximum de vitesse, on peut faire s'autcmodifier le code et le
* supprimer, mais ce n'est pas très élégant et nous ne l'avons
* pas fait, d'autant que le gain est peu élevé ( cmp.l + dble
* =20 cycles et 3 N3P = 12 cycles) sauf en misant beaucoup.
* ; Arrivé ici, le calcul est presque terminé. Il ne reste plus qu'à
* diviser PI par 5 et Tenp par 239 move.l 239,dl ; Csi divise temp
move.1 a2,a3 ;
add.l d6,a3 ;
move.1 d2,d6 ;
moveq 0,d5 ;
Fois moveq 0,d4 move.w -(a3),d4
lsl.w add.w divu move.w swap move.w
move.l
bsr
a0,a3
Div
moveq 5,dl move.1 a2, a3 bsr.s Div EndArctg: rts
* ****** 1ère routine de division
* paramètres: a3 pointe sur la variable à diviser
*
dl contient
le diviseur
Div move. 1
32,d6
Taille variable dans d6
moveq
0,d4
d4 est utilisé pour le reste
moveq
0,d5
et d5 pour le calcul
Divise mulu 10000,d4
; Reste * 10000
move.w
(a3),d5
ncmbre suivant dans d5
add.l
d5,d4
on ajoute le reste
divu
dl,d4
et on divise
move.w
d4,(a3)+
on range le quotient
clr.w
d4
et on l'efface de d4
swap
d4
d4 contient maintenant le reste
dbf
d6,Divise ;
On boucle
rts
;
c'est déjà terminé !
* ****** Seconde routine de division
move.l addq.l move.l move.l move.l move.l addq.l Aff move.w
a2,a4 ;
a0,a3 ;
l,a3 ;
(a4) +,d6 lea Tabrang,al ; moveq 3,dl ;
Rang move.w (al)+,d4 moveq -$ 30,d5 ;
Divl move .1 d2, d6
move.l
al,a3
move.l
1000,d4
divu
d0,d4
move.w
d4,(a3)+
clr.w
d4
swap
d4
Divise2 mulu 10000,
divu
d0,d4
move.w
d4,(a3)+
clr.w
d4
swap
d4
dbf
d6,Divise2
rts
Tabrang:
dc. w
1000,100,10,1
dO = dO -2 (rappel:dO = 2n+l)
on va diviser PI (càd Arctg 1 5)
par 25
c'est fait
On calcule l 2n+l
a4 pointe sur PI
PI = l 2n+l-PI
calcul de arctg 239 débuté ?
Non -> Dev
Oui, on divise Tenp
par 239*239=57121
Et hop !
Temp = l 2n+l - Temp Et hop !
On boucle
Taille dans d6 On divise Bis
On calcule les leres décimales de l 2n+l dans d4 et on les range puis on garde le reste dans d4
; reste * 10000
on divise par 2n+l on range le quotient et on ne garde que le reste dans d4 on boucle Au revoir !
Par 239 Ok!
Idem pour PI mais division par 5 Right !
; Ouf! Le plus gros est fait !
Add.l d6,a4 ; Fin de la BIS -> a4
move.l d2,d6 ; Taille (en mots) -> d6
and $ ef,CCR ; On efface le bit X de OCR
Moins move.w -(a3),d5 ; On va effectuer la soustraction
move.w -(a4),d4 ; a4-a3, le 68000 gérant le report
subx.w d4,d5 ; de la retenue grâce au bit x !
Bpl. S Pas_retenue ; test retenue Retenue add.w 10000,d5 ; oui on ajoute 10000
Pas_retenue:
move.w d5,(a3) ; on range le résultat dbf d6,Moins ; et on boucle rts ; Tchao !
* ****** Seconde routine de soustraction
Subtemp move. 1 Taille,d6 ; Taille dans d6
Soust sub.w d4,d6 ; tant que d4>0, d4=d4-d6
dfcmi 35,Soust ; et d5=d5-l
neg.b 35 ; code ascii du chiffre dans d5
move.b 35, (a 3)+ ; on le range dans le tampon
add.w d4,d6 ; et on replace d6
dbf dl,Rang ; chiffre suivant dbf d7,Aff ; mot suivant
move.l a0,a3 ; a3 pointe sur Bis
move.b I(a3),(a3> ; Déplace le 1er chiffre move.b '.',l(a3) ; Et ajoute '.' à la suite
add.l Nbdec,a3 ; a3 pointe sur la fin de chaîne
move.b $ 0a,2(a3) ; Retum
move.l Stand_output,dl ; sortie courante -> dl move.l a0,d2 ; Adresse chaîne = Bis
jsr _LVCWrite(a6) ; On affiche rts ; C'est la FIN, sniff !
PI pointé par a3 Fin de PI pointée par a3 Taille -> d6 d5 initialisé ; d4=0
,- mot suivant -> d4 2,d4 ; d4=d4*4
d5,d4 ; d4=d4+retenue
10000,d4 ; on calcule le reste et d4,d5 ; la retenue qui est placée dans d5
d4 ; le reste est lui d4, (a3) ; rangé dans PI dbf d6,Fois ; On boucle rts ; end !
* ****** Routine d'affichage
* Remarque: on se set de Bis et de Temp comme tampon d'affichage AffichePI
Nbdec,d3 ; Nb dec -> d3 3,d3 ; d3=d3+3 pour le retum de fin & 3.
D2,d7 ; Taille (mots) -d7
_DOSBase,a6 ; a5 pointe sur dos.library
subx.w bpl. S Retenue2:
add.w 10000,d5 Pas_retenue2:
move.w d5,(a4) dbf d6,Moins2 rts ; Adios !
* ****** routine de multiplication Mulpi4 move.l Taille,d6 ; Taille -> d6
a4 sur PI et a3 sur Bis
On laisse la place pour '.'
; mot à convertir table de conversion 4 chiffres
; valeur suivante de la table
- code ascii de 0 dans d5
move.l al,a3 add.l d6,a3 add.l d6,a4 move.1 d2, d6 and $ ef,CCR Moins2 move.w -(a3),d5 move.w -(a4),d4 d4,d5
Pas retenue2
Table de conversion
lere routine de soustraction
Taille (en octets) -> d6 a4 sur bis a3 sur PI
Fin de PI -> a3
ib move.l Taille,d6 move.1 aO, a4 move.l a2,a3 add.l d6,a3
Il est des cas fréquents, sur une machine multitâche, où plusieurs programmes ont besoin de communiquer entre eux : le domaine public regorge d'exemples d'utilitaires initialisant des tâches de fond, auxquelles le programme principal pourra plus tard transmettre diverses informations suivant ses besoins du moment.
Ais l'exemple le plus évident est encore Intuition et ses fameux flags IDCMP. Dont notre docteur national vous entretient des qu'il en a l'occasion, avec tout le brio qu'on lui connaît : chaque fois qu'intuition a besoin de signaler à une application un événement particlier, elle le fait par le biais d'IntuiMessages. Qui contiennent toutes les informations nécessaires (type de l'événement, position de la souris au moment où il est survenu, état du clavier et plus particulièrement des touches spéciales, heure système...).
M
Ce mécanisme de communication inter-tâches fait partie intégrante d'Exec. à travers ses signaux et ses ports de messages. Le principe est à la fois fort simple et ingénieux : les tâches communiquent entre elles au moyen de ports de messages (MsgPort). Qui sont autant de boîtes à lettres grâce auxquelles elles peuvent s’envoyer des petits mots d'amour (Messages). Et comme les tâches sont des gens très polis, elles se font un devoir de répondre à chaque message, juste histoire de signaler à l'envoyeur qu'il a bien été reçu. Le seul rôle d'Exec dans tout ça est de véhiculer les messages d'un port à l'autre. Pour continuer l'analogie ci-dessus, c'est Monsieur P&T en personne.
MORDS-MOI LE NOEUD
L'une des particularités du système d'exploitation de l'Amiga est de ne disposer d'aucune adresse fixe (homiis l'adresse 4. Qui contient un pointeur sur la structure ExecBase). Celà signifie plus précisément, qu'un programme ne peut jamais savoir où se trouve en RAM une structure particulière sans d’abord la rechercher explicitement. C’est pourquoi Exec offre un mécanisme de localisation basé sur le principe des listes chaînées : chaque membre de la liste contient un pointeur sur son prédécesseur et sur son successeur. Ainsi, en parcourant la liste, on peut facilement retrouver un membre particulier. Ce principe a un autre avantage, la rapidité : on peut facilement ajouter ou supprimer un membre de la liste simplement en modifiant quelques pointeurs, alors que dans le cas d'une liste séquentielle (les membres sont à la suite les uns des autres), on serait obligé de procéder à un déplacement de bloc mémoire coûteux en temps machine, et donc en performance du système. Dans la terminologie de l'Amiga. Un membre d'une liste est appelé un noeud (Node). Exec tout entier repose sur le principe des noeuds et des listes. Le lecteur averti - celui qui en vaut deux - pourra toujours sauter le paragraphe suivant s'il en connaît déjà le principe. Pour le novice, précisons simplement que les listes sont largement utilisées par les ports de messages et qu'il convient donc d'en saisir parfaitement le fonctionnement avant que d'aller plus loin.
ON ENCHAINE
La sagesse populaire dit qu'il faut un début à tout : une liste chaînée n'échappe pas à cette règle. Comme on y est maintenant habitué avec l'Amiga. Le début d'une liste est représenté par une structure C. que l'on trouve dans les includes "execAists.h" et "exec lists.i" :
struct List
struct Node *Lh_Head; struct Node *lh_Tail; struct Node *lh_TailPred;
UBYTE lh_Type;
UBYTE l_pad;
};
IhJHead est un pointeur sur le premier noeud de la liste. Lh_Tail est toujours NULL. Et lh_TailPred pointe sur le dernier noeud de la liste. Une liste est dite vide lorsqu'elle ne contient aucun noeud, c'est-à-dire lorsque le champ lh_TailPred pointe sur une valeur nulle et lh_Head. Sur la liste elle-même. Lh_Type contient un code indiquant le type de la liste, et Lpad fait en sorte que la structure contienne un nombre pair d'octets.
NOTE : le fichier "execAists.h" tel qu'il est fourni avec le compilateur SAS Lattice C 5.10 fait état d'un champ "Ij>ad" alors que la logique voudrait que ce soit "Ih_pad". Je préfère quant à moi m'en tenir à la version Lattice. Puisque c'est elle qui sera utilisé en cas de référence à ce champ dans un programme.
Un noeud est également représenté par une structure, que l'on trouve cette fois-ci dans "exec nodes.h" et "exec nodes.i" :
struct Node
struct Node *ln_Succ; struct Node *ln_Pred;
UBYTE Ln_Type;
BYTE ln_Pri; char ’lnName;
};
ln_Succ pointe sur le prochain noeud de la liste et ln_Pred. Sur le précédent. Le dernier noeud d'une liste est caractérisé par un champ ln_Succ initialisé à 0 (NULL). Ln_Type indique le type du noeud (évidemment, une liste d'un type donné ne peut contenir que des noeuds du même type) et ln_Pri sa priorité au sein de la liste. Enfin. Ln_Name pointe sur une chaine de caractères pouvant représenter le nom du noeud, défini au gré du programmeur, et qui pourra être utilisé pour retrouver un noeud particulier par son nom.
Voilà. La dernière chose que l'on puisse dire sur les listes, est que la bibliothèque exec.library fournit toute une rimbambelle de fonctions pour leur gestion : initialisation, insertion, suppression et recherche de noeuds sont au menu du jour.
SIGNAL SANS FLUOR
Le signal est le niveau le plus simple et le plus performant à la fois de la communication inter-tâches. Leur utilisation la plus simple consiste simplement à synchroniser deux tâches entre elles (ADLR : vous en avez un exemple flagrant dans l'utilitaire du mois, le ScreenSaver). Mais ils sont également utilisés, justement, dans les ports de messages.
Chaque tâche peut disposer d'un maximum de 32 signaux, qui correspondent à autant de bits du champ tc_Sig Vait de sa structure Task. Sur ces 32 signaux. 16 sont réservés par le système pour des événement particuliers, par exemple les 4 "break" possibles (CTRL C. CTRL D. CTRLÆ et CTRL F). Les 16 autres sont à la disposition de la tâche, qui peut leur assigner les événements qu'elle désire. Ceci est très important : le signal numéro 13 peut signifier pour une certaine tâche qu'un temps donné vient de s'écouler, alors que pour la tâche voisine, il signifiera peut-être qu'un message vient d'arriver sur son port.
Une tâche alloue un signal avec la fonction AuocSignaK). Il faut en effet savoir que chaque fois qu'une tâche crée, directement ou non. Un port de message (par exemple, en ouvrant une fenêtre avec des flags IDCMP). Un nouveau signal lui est alloué par le système. En d'autres ternies, si elle désire se réserver un signal particulier, elle doit le faire de manière à ce que ce signal ne soit pas ré-utilisé à son insus. D'où l'utilité d'AllocSignal(). Cette fonction demande en paramètre le numéro du signal à allouer, où -1 pour le prochain libre. En pratique, on transmet toujours -1. Laissant ainsi à Exec le soin de choisir le bon signal. En retour. AuocSignaK ) transmet le numéro du signal alloué, ou -1 si aucun n'était disponible. En C. celà donne :
BYTE signal;
signal = AllocSignal(-lL); if (signal == -1)
printfCPlus de signal libre-); else
printf(“Signal numéro %d alloué", signal);
Lorsqu'un signal n'est plus nécessaire, il doit être libéré au moyen de la fonction FreeSignalO :
FreeSignal(signal);
Avant que de pouvoir être utilisé, un signal doit être converti en masque, ceci afin d'accélérer le traitement de la demande par Exec. Ceci se fait de manière très simple, par l'instruction suivante :
ULCNG signalmask; signalmask = IL signal;
Une tâche peut alors attendre qu'un ou plusieurs signaux qu’elle a alloué surviennent (encore une fois, les signaux peuvent lui être alloués indirectement par le système) au moyen de la fonction Wait(). Qui demande en paramètre le masque du (des) signal (aux) à attendre. Par exemple, imaginons un programme ayant ouvert une fenêtre avec un menu (disposant donc de flags IDCMP) ainsi que l'input.device. et qui peut se faire signaler par un serveur d’interruption qu'il a mis en place, qu'un temps donné vient de s'écouler. En C. cela ressemblera à quelque chose du genre :
* la fenêtre et l'input.device sont déjà ouverts ! *
BYTE irqSignal;
ULONG windowMask, inputMask, irqMask;
ULON3 signal_recu;
windowMask = IL window->UserPort->mp_SigBit; inputMask = IL inputPort->mp_SigBit; if ( (irqSignal = AllocSignal(-lL)) == -1 )
printf("Plus de signal pour 1'interruption"); exit(-l);
else
irqMask = IL irqSignal;
* attente d'un ou plusieurs des 3 signaux possibles * signal_recu = Wait(windowMask I inputMask I irqMask); if (signal_recu & windowMask)
printf("Une option de menu a été choisie");
if (signal_recu & inputMask)
printf("Une touche a été appuyée");
if (signal_recu & irqMask)
printf("Le temps s'est écoulé");
Rappelez-vous qu’une tâche donnée peut attendre jusqu’à 16 signaux simultanément.
Enfin, pour envoyer un signal, une tâche doit d'abord savoir à qui elle va l'adresser, et bien sûr, quel signal envoyer (n'oubliez pas que chaque tâche dispose de ses propres signaux). C'est pourquoi deux tâches qui désirent communiquer ne peuvent le faire que si les deux sont parfaitement au courant de ce qui va se passer. Quand la tâche émettrice signale la tâche réceptrice, elle utilise la fonction Signal(). Qui demande en paramètre l'adresse de la tâche à signaler, et le masque du signal à lui envoyer :
Signal(task, signalmask);
LES MARINS QUI PISSENT
Dans le port de message, on retrouve le signal en tant que base de la communication. Un message est composé de deux parties distinctes : une utilisée par Exec pour envoyer le message à bon port, l'autre étant le corps même du message. Cette partie est entièrement et librement définissable par le programmeur, qui peut donc en faire ce qu'il veut, dans la limite toutefois de... 64 Ko !
Les messages sont envoyés sur des ports de messages (MsgPort), selon un système de file d'attente : le premier message arrivé sur un port en est le premier extrait (en anglais, first in first out, ou encore FIFO). Il n'y a aucune restriction autre que la quantité de mémoire disponible, quant au nombre de ports dont une tâche peut disposer et au nombre de messages qui peuvent arriver sur chaque port.
Pour des raisons de performance, Exec ne procède pas à la copie des messages dans une mémoire tampon. En clair, celà signifie que si une tâche A envoie un message à une tâche B. les deux tâches vont se partager - provisoirement - l’espace mémoire occupé par ce message. La tâche A doit donc faire attention à ne pas modifier le contenu du message avant que la tâche B en ait terminé avec celui-ci, ce qu’elle indique en renvoyant le même message à la tâche A. Exec offre bien entendu toute une panoplie de fonctions dédiées à l’envoi, l'attente, la réception et la réponse aux messages.
SALUT LES PORTS
Les ports de messages sont donc en quelque sorte des points de rendez-vous où tous les messages destinés à une tâche particulière arrivent. En fait et pour être plus précis, tous les messages destinés à une tâche particlière et envoyés par une autre tâche non moins particulière. En d'autres termes, si une tâche désire communiquer avec - par exemple - Intutition. Le console.device et le trackdisk.device, elle devra posséder 3 ports de messages, un par tâche communicante.
Encore une fois, c'est une structure C qui définit l'aspect d'un port de messages. On trouve sa définition dans les includes "exec ports.h" et "exec ports.i" :
struct MsgPort struct Node rnp_Node;
UBYTE np_Flags;
UBYTE jip_SigBit;
struct Task *mp_SigTask; struct List mp_MsgList;
};
Le premier champ de cette structure. Mp_Node, est un noeud standard, qui peut être utilisé pour donner un nom à ce port (par l'intermédiaire du champ ln_Name de la structure Node). Ceci peut se révéler très pratique lorsqu'une tâche désire savoir si une autre tâche est déjà présente en mémoire : grâce à la fonction FindPort(nom), elle peut très aisément s'en rendre compte (NLDR : encore une fois, jetez un oeil sur l'utilitaire ScreenSaver de ce mois-ci).
Le champ mp_Flags indique à Exec ce qu'il doit faire lorsqu’un message arrive sur ce port. Avec PA_SIGNAL. Exec signale - par la fonction Signal() - à la tâche désignée par mp_SigTask. L'arrivée du message ; avec PA_SOFTiNT. Une interruption est déclenchée ; enfin, avec PAJGNORE. Rien ne se passe, le message est simplement inséré dans la file d’attente.
Mp_SigBit contient le numéro du signal alloué à ce port. Mp_SigTask est un pointeur sur la tâche devant être signalée lorsuqu'un message arrive sur ce port (si mp_Flags == PA_SIGNAL). Et mp_MsgList est le début de la liste des messages déjà arrivés sur ce port.
Pour se créer un port de messages, une tâche doit donc initialiser une structure MsgPort en remplissant correctement le noeud et en initialisant la liste. Si ce port doit être rendu publique, c’est-à-dire si d’autres tâches peuvent y accéder, elle devra de plus appeler la fonction AddPortO d'exec.library. Heureusement, la fonction CreatePort() contenue dans amiga.lib. simplifie tout ce processeur de création. Elle demande pour paramètre le nom du port à créer (ou NULL s’il ne doit pas être rendu publique) et sa priorité :
monPort = CreatePort("Max.Port", NULL);
Quand une tâche n'a plus besoin d'un port, elle doit le supprimer de la liste des ports publiques le cas échéant - c'est-à-dire s’il y avait été inséré avec AddPortO - au moyen de la fonction RemPort(). La fonction d'amiga.lib DeletePortO s'occupe de tout ça ; il suffit de lui transmettre un pointeur sur le port à supprimer :
DeletePort (monPort ) ;
Tous les messages restant dans la file d’attente de ce port devront en avoir été enlevés, ce qui s’obtient en y répondant jusqu’à ce la file soit vide.
Mais je parle, je parle, et je constate que la place qui m’était impartie est bien remplie. Nous verrons donc le moins prochain les messages et leurs différents types (depuis les messages standards d’Exec et Intuition jusqu'aux messages personnels qu’une tâche peut envoyer) et mettrons enfin en pratique tout ce qui vient d’être dit. Asta la vista !
Z) eM.r utilitaires du domaine public pour le prix d’un : c’est ce que vous propose notre ToolBox de ce mois. Et qui plus est, ces deux utilitaires n ’ont aucun point commun entre eux
& PARNET
Le premier. ReqLib. Est une bibliothèque Amiga standard, totalement ré-entrante, destinée à faciliter - et à uniformiser - la création de requesters. Elle dispose notamment d'un puissant FileRequesier pouvant être utilisé en tant que FontRequester. D'un ColorRequester. Et de StringRequesters supportant des opérations de formatage du texte, façon printfO. Req.library s'utilise exactement comme une bibliothèque système (dos. Intuition...) : il faut d'abord l'ouvrir, mémoriser son adresse de base, puis la fermer lorsqu'on n'en a plus besoin. Elle est évidemment utilisable aussi bien depuis l'assembleur que depuis le C (A tec ou Lattice). En fait, n'importe quel langage, même l'AmigaBasic. Convient 1
Exemple d'ouverture en C :
Sinclude "1ibraries req.h"
struct Req3a.se *Rec3ase = NOLL;
maint)

* Ouverture de la req.library *
Req3ase=(struct ReqBase *)OpenLibrary("req.library",OL); if (!Req3ase)
CleanExitC'Pas de req.library !");
CloseLibrary(Req3ase);
}
Le même, en assembleur :
include "libraries req.i"
; Ouverture de la req.library lea reqname(pc),al noveq 0,d0 CALLEXEC OpenLibrary raove.1 dO,_Req3ase beq NoReq ; ouverture ratée
movea. 1 _Req3ase (pc), al CftXJaXBC CloseLibrary
Panant de là. Les fonctions listées ci-dessous (et classées par thème), sont disponibles.
- Affichage d'un requester de type AutoRequcst. Mais plus évolué :
SimpleRequest()Requester à 1 bouton ¦pwoGadRequest ( ) Requester à 2 boutons TextRequest() Requester à 3 boutons
- Affichage d’un requester de chai ne :
GetString Requester de chaîne de caractères GetLong Requester de nombre 32 bits
- Affichage d'un sélecteur de fichier)s) ou de fonte(s) :
FileRequester()
PurgeFilesO
- Affiche un requester de palette :
ColorRequester()
- Création dynamique de gadgets (pour programmes ré-entrants) :
Alloue un gadget booléen Alloue un string gadget Alloue un gadget proportionnel Alloue un gadget booléen Alloue un gadget proportionnel
MakeGadget() MakeString() MakePrcpO KakeButton() MakeScrollBarf)
Gestion des gadgets proportionnels : SetSizeo"
ReadLocationO
SetLocationO
- Gestion des gadgets liés à une fenêtre :
LinkGadget()
Linkst r ir.gGadget ( )
LinkPropGadget )
- Routines diverses :
DrawBox Dessine un rectangle d'un coup
GetFontwidthAndHeignt Renvoie la taille de la fente RealTimeScroll Scrollirg suivant un ascenceur RawKeyToAscii Conversion touches RAW er. ASCII Center Centrage d'une fenêtre
Format Formateg de texte à la sprintfO
Il serait vain de décrire ici toutes ces fonctions, une à une. L'archive de distribution contient un exemple d'utilisation de la req.library. ShowOffReq. Démontrant une grande partie de ces fonctions (en fait, toutes celles qui ont un résultat visible à l'écran).
Une bibliothèque étant faite pour les programmeurs, divers fichiers includes sont fournis, tant pour lès.adeptes du C que pour ceux de l'assembleur. Ce sont req.h. reqbase.h et reqbase.i (étonnant, non ?) Qu'il conviendra de placer dans votre répertoire Include:Libraries . Un fichier reqproto.h est également fourni, pour utilisation avec le Lattice. Concernant l'assembleur, reqbase.i est écrit comme les autres includes standards de Commodore, à savoir en utilisant les macros STRUCTURE. LABEL et autres LONG, et non avec la pseudo-instruction "rs" du Devpac (bien que Devpac comprenne également cette forme, l'assemblage est plus rapide avec "rs"). Par contre, reqbase.i contient également les définitions des Library Vector Offsets (_LVOxxx). Alors qu’il eût été plus logique de les mettre à part, dans reqjib.i par exemple (ce pour rester conforme avec la structure des autres includes). Enfin, un fichier nommé macros.i contient devinez quoi ? Quelques macros destinées à vous faciliter la vie.
Deux autres fichiers objet, areqglue.o et Ireqglue.o sont plus particulièrement destinés à être linkés avec votre code. C ou assembleur, suivant l'utilisation que vous désirez faire de la req.library. Il s'agit de ce que l'on nomme des routines "glue”. C'est-à-dire des bouts de routines destinés à faciliter l'interfaçage avec d'autres routines, plus complexes. En F occurence, on y trouve les routines récupérant les paramètres depuis la pile dans les registres adéquats puis appelant les fonctions de la biliothèque (ceci plus particulièrement pour le langage C) et la définition des fonctions SimpleRequesK) et TwoGadRequestO. Qui ne sont que des simplifications de l’appel à TextRequest. Qui elle fait partie intégrante de la bibliothèque (heu... Ca va. Vous suivez encore ?). Areqglue.o est destiné au compilateur ou à l'assembleur Aztec. Tandis que Ireqglue.o est destiné au Lattice.
Un petit programme supplémentaire, nommé CustomizeFile et dont le source est fourni, montre comment "patcher" les fonctions de la bibliothèque (avec SetFunctionO d'exec.library ) pour, par exemple, customiser le FileRequester.
Dernier point important, la documentation req.doc liste toutes les fonctions de la bibliothèque de manière détaillée, avec syntaxe, description des paramètres, effet, bugs connus... exactement à la manière du RKM Includes & AutoDocs.
ReqLib est un programme de Colin Fox (de Pyramid Designs) et de Bruce Dawson (de CygnusSoft Software). Il est librement distribuable. Mais n'est pas placé dans le domaine public (c'est-à-dire que les sources ne sont pas fournis, et que vous n'avez pas le droit de modifier le code exécutable). Vous pouvez l'utiliser dans vos propres programmes, même commerciaux, sans payer ne serait-ce que l'ombre d'une royaltie aux auteurs. A ma connaissance, de nombreux programmes utilisent déjà la req.library. dont The Art Department de ASDG. Inc. et ImageLink de Active Circuits. Inc.
PARNET
ParNet n'a absolument aucun rapport avec ce qui précède : il s'agit d'un mini-réseau 2 postes fonctionnant avec le port parallèle de F Amiga (d'où le nom de "ParNet". Etonnifiant. Non ?).
ParNet permet donc à deux Amigas de co-exister de manière tout-à-fait transparente pour l'un comme pour l'autre. Chacun pourra avoir accès aux devices de l'autre comme s'il s'agissait des siens (lecteur de disquette, disque dur. Imprimante, etc.).
Devant la complexité d'un tel logiciel, nous avons décidé de traduire la documentation originale. Pour respecter les voeux des auteurs, nous ne pouvons malheureusement pas inclure la nouvelle documentation dans la distribution, aussi la voici ici imprimée.
L_o_ol Copyright (c)
1988, 1989, 1990 The Software
Distillery.
I. o.I I
1 Ail Rights
Reserved
I . I II
Written by Doug Walker and
John Toebes
I o I |
1 The Software
Distillery
I . I
405 B3 Gooseneck Drive
Cary, NC
27513
PLINK: EMALKER BIX:
DJWALKER
BBS:(919)-460-7430 Deep
Thought
*
LISEZ LE FICHIER REAEME DANS CETTE DISTRIBUTION POUR AVOIR DES INFORMATIONS IMPORTANTES SUR LE COPYRIGHT. CONTACTEZ LES AUTEURS AUX Addresses CI-DESSUS SI VOUS N'AVEZ PAS CE FICHIER.
Traduction Française par Stéphane SCHREIBER
INSTALLATION DU RESEAU:
1. Fabriquez un cable d'après les instructions incluses dans le fichier 'Cable.doc' ci-joint. Connectez les deux Amigas.
2. Copiez pamet.device dans les répertoire DEVS: des DEUX macgines.
3. Insérez une entrée pour le réseau dans le fichier DEVS:MOUNTLIST des deux Amigas. Vous pouvez simplement ajouter le fichier 'mountlist' fourni dans cette distrubution à la fin de votre DEVS:MOUNTLIST en utilisant un éditeur de textes quelconque.
Choisissez la machine qui sera l'UNIT 1 et mettez la ligne 'Unit =' de sa MX1NTLIST à 1.
4. Copiez netpnet-handler dans le répertoire L: des deux machines.
5. Copiez netpnet-serveur dans le répertoire C: des deux machines.
MISE EN ROUTE DU RESEAU:
1. Lancez les deux serveurs NET:. Sur la machine déclarée en UNIT=0 dans
la nnuntlist, démarrez le serveur avec la commande NETPNET-SERVEUR UNIT 1 Sur la machine déclarée en UNIT=1 dans la mountlist, tapez NETPNET-SEKVER UNIT 0 ou bien, UNIT 0 étant le défaut, vous pouvez simplifier NETPNET-SERVER
La raison de cette inversion des UNIT est que vous démarrez un serveur NET: sur l'AOTRE machine.
2. Tapez une commande MOUNT sur les deux Amigas:
MOUNT NET:
3. NET: est maintenant prêt. NET: apparaîtra canne vide la première fois
que vous en demanderez le DIRectory depuis le CLT. Vous pouvez accéder aux devices de l'autre machine en spécifiant NET:device chemin (par exemple, NET:DHO C LIST). De cette manière, NET: prendra en ccnpte l'autre device. Le device (DHO dans ce cas) apparaîtra alors dans le DIRectory de NET:. Aucune icône de tiroir n'apparaîtra dans la fenêtre NET: du Workbench tant que vous ne l'aurez pas forcé à les lire. La ccmnande
CD NET:device
suffit amplement à initialiser le device 'device'.
Le 'device' peut être n'importe quel device AmigaDOS ou volume valide sur l'autre machine.
4. Si vous voulez utiliser NET: avec le Workbench, vous devez fournir une
icône pour chaque device pris en compte sur l'autre machine. Pour ce faire, copiez n' importe quelle icône de tiroir en NET :device.info après avoir pris en ccnpte le device 'device'.
CD NET : DHO ; Prends DHO en ccnpte
COPY SYS:C.INFO NET:DHO.INFO ; Lui fabrique une icône
Vous n'avez besoin de faire tout ça qu'une fois pour les disques durs et autres devices permanents, mais RAM: perdra son icône chaque fois que vous ré-initialiserez l'Amiga, vous obligeant à recopier l'icône. (NOTE: un fichier ncnrné 'node.rinfo' apparaîtra dans la racine de l'autre device. NET: y stockes les icônes que vous lui spécifiez. Si wus supprimez ce fichier, vous supprimez toutes les icônes en même temps).
Notez que si vous effectuez un DIRectiory de NET:, vous verrez toujours les fichiers '.info' des devices de l'autre machine, MEME S'ILS N'EXISTENT PAS. NET: assume que si les icônes sont là, le device également et ne vérifie pas plus avant, sauf nécessaire. Si les '.info' apparaissent avec la ccmnande DIR mais pas sous Workbench, vous devrez copier une icône de tiroir dans NET: canne décrit plus haut.
La ccmnande NETSTAT donne une représentation visuelle du travail du réseau
Lancez la par KUN NETSTAT NET:
et fermez la fenêtre pcsur quitter.
Verions et améliorations :
VERSION 08 90
- Corrections pour AmigaDOS 2.0
- Support Reset amélioré
- Supporte la connection bilatérale
- Supressian d'un niveau de copie de donnée pour gagner en vitesse VERSION 04 90:
Deuxième version du port parallèle
- Plusieurs bogues mineurs corrigées
- ACTICN_SET_DATE inplémenté
- Le Reset d'une machine est indépendant de l'autre
- Utilisation du ncmveau pamet.device de Matt Dillon VERSION 08 89:
Preçdère version du port parallèle VERSION 07 18 89:
- Vitesse accrue grâce à la réduction de la taille des paquets Augmente la vitesse de chargement des programnes par le réseau et celle des opérations de directory.
- Suppression du code de debogage
Rend le code exécutable plus compact et rapide.
- Bogue corrigé dans ACTION_CREATE_DIR
VERSION 05 09 89:
Première version, avec DNET
par
L’utilitaire de ce mois va vous permettre de sauvegarder en tant qu ’ image IFF, n ’importe quel écran Intuition ouvert au moment de son invocation.
A
SAUVEUR D’ECR
Ce type d'utilitaire existe déjà dans le domaine public, le plus célèbre étant - je pense - ScreenX. De Steve Tibbett (également auteur de VirusX). Malheureusement, ScreenX agit selon un principe qui ne me plaît guère : il ouvre une (petite) fenêtre sur le Workbench lorsqu'il est inactif et carrément un Custom Screen lorsqu'il est actif. Un petit panneau de contrôle est alors proposé, qui permet de choisir entre tous les écrans ouverts, celui qui sera sauvegardé, voire imprimé. Bon.
De mon côté, je préfère et de loin le principe de YASS! (pour "Yet Another Screen Saver !". Les adeptes d'Unix reconnaîtront la référence) : il ajoute un handler à la chaîne d'événements gérée par l'input.device. tout comme le CRBlanker de Frédéric Mazué, proposé dans ce même magazine quelques mois plus tôt. Dès lors, à chaque fois qu'une certaine combinaison de touches est pressée, en l'occurence CTRL ALT DEL (encore une référence...), l'écran de front est sauvegardé par le programme principal dans un fichier IFF tout-à-fait standard, visualisable et éditable par n'importe quel soft de dessin capable de comprendre ce format (c'est-à-dire tous).
PRELIMINAIRES
La routine d'installation de l'input-handler est maintenant classique : on ouvre l’input.device et à l’aide de la commande IND_ADDHANDLER. Le handler est ajouté à la chaîne. Sa priorité est de 101. Ce qui est amplement suffisant pour le placer en premier dans la chaîne (rappel : l'input-handler d'intuition dispose d'une priorité de 51). Dorénavant, chaque fois qu'un événement survient (souris, joystick, clavier...), le contrôle passe d'abord par notre handler. Qui vérifie dans un premier temps que la tâche principale n'était pas déjà en train de sauvegarder un écran, et dans un deuxième temps, que la bonne combinsaison de touches a été pressée. Si ces deux conditions sont remplies, il envoie un signal à la tâche principale, qui commence alors son travail. Notez au passage que vous trouverez dans le listing, un équivalent assembleur des fonctions CreatePort('), DeletePort(), CreateExtIOO et DeleteExtlOQ de famiga.lib (je déteste linker !).
IFF
Le fichier EFF sauvegardé est parfaitement standard : simplement, les gens de chez Electronic .Arts piqueraient sans doute une crise cardiaque s'ils voyaient de quelle manière on s'y prend...
L'écriture d'un fichier IFF est moins aisée que la lecture : il faut d'abord connaître la taille de chaque chunk avant de pouvoir l'inscrire dans le fichier. Or. Pour connaître la taille d'un chunk. Il faut justement l'avoir déjà écrit... Ce qui oblige à quelques jongleries avec le DOS et la fonction Seek().
Pour éviter celà. On utilise un petit truc : sachant d'une part que l'on n'écrit que les chunks réellement indispensables (BMHD. CAMG. CMAP et BODY) et que d'autre part, le BODY n'est pas compressé, on peut connaître la taille de la FORM avant même de l'avoir écrite : les chunks BMHD et CAMG sont de longueur constante (respectivement 20 et 4 octets), seule les tailles du CMAP et du BODY sont à calculer. Ce calcul ne pose toutefois aucun problème, tous les paramètres étant issus de la structure Screen et du RastPort de l'écran à sauvegarder. A la taille ainsi calculée, on ajoute encore quelques octets nécessaires aux différents identificateurs de chunks. Pour résumer, la taille de la FORM IFF sera :
- 4 octets pour "ILBM" ("FORM" et sa taille ne sont pas comptés) ;
- 28 octets pour le BMHD :
- 12 octets pour le CAMG :
- 8 octets pour "CMAP". Sa taille, et le CMAP lui-même :
- 8 octets pour "BODY”. Sa taille, et le BODY lui-même :
soit 60 octets, plus la taille du CMAP. Plus la taille du BODY (essayez, vous verrez bien).
Pour ne pas allonger inutilement le programme, le nom du fichier à écrire est inclus directement dans le source : il s'agit de "Ram:ScreenSaver.image". Ce qui implique qu'à chaque sauvegarde, l'ancienne est écrasée. Il ne tient qu'à vous de modifier celà.
Max
se prend pour Le Sauveur
* Programne : Screensaver
* Version : 1.1
* But : Sauvegarder l'écran ce front en image I??
* Auteur : Max pour ANT
* Date : 22 Avril 1991
* langage : Assembleur Devpac II v2.14
inedir "Include:" inc lude " exec irenory. I " include "exec io.i" include "exec interrupts.i" include "intuition intuition.i” include "intuition intuiticnbase.i" include "graphics gfx.i" include "libraries dos ¦ i” include "devices input ¦ i" include "devices inputevent.i”
include "exec exec_lib.i" include "intuition intuition_lib.i" include "libraries dos_lib.i"
opt o+,ow- ; pour retirer les offsets inutiles
; Quelques macros utiles
EXEC MACRO CALLEXEC 1 ENIM
DÎT MACRO
movea.l IntBase(a5) ,a6 jsr _LV01(a6)
ENIM
DOS MACRO
movea.l DosBase(a5) ,a6 jsr _LV01(a6)
ENIM
REV EQU 33
CAM3MSK EQU (-(V_SPRITESIGENLOCK_VTDEO)&$ OOOOFFFF)
CTRLED EQU IEQUALIFIER_COOTROL
ALTED EQU IEQUALIFIER_LALT ! IEQCALIFIER_RALT
QUALMSK EQU CTRLED I ALTED
QOALl EQU CTRLEDIIEQUALIF1ER_LALT
QUAL2 EQü CTRLEDIIEQÜALIFIER_RALT
; * Définition du BMHD façon include rsreset BitMapHeader rs.b 0 tmhd_w rs.w 1
fcmhd_h rs.w 1
bc!hd_x rs .w 1
tmhd_y rs.w 1 tmhd_nPlanes rs.b 1
SISIFF
HBESEtriMiUaSMliÉÉMMlRSSISCB
fcœhd_Masking rs.b 1
tmhd_Ccmpression rs.b 1 tmhd_padl rs.b 1 fcmhd_transparentColor rs.w 1 bmhd_xAspect rs.b 1
fcmhd_yAspect rs.b 1
bmhd_pageWidth rs.w 1
bmhd_pageHeightrs.w 1 fcmhd_SIZEOF rs .w 0
; * Définition des variables du programme (pointées par a5) rsreset
args
rs.l
2
Arguments du CLI
IntBase
rs.l
1
Adresse de base d'intuition.library
DosBase
rs.l
1
Adresse de base d'exec.library
myTask
rs.l
1
Ma propre tâche
myPort
rs.l
1
MsgPort
nylO
rs.l
1
IOStdReq pour l'input.device
busy
rs.b
1
TRUE si en train de sauver un écran
iffSig
rs.b
1
n‘ du signal alloué pour IFF
iffMsk
rs.l
1
Mask du signal IFF
filehd
rs.l
1
FileHandle du fichier de sauvegarde
windcw
rs.l
1
Fenêtre active au manent de sauver
pointer
rs.l
1
Sauvegarde du pointeur de souris
ptrsize
rs.l
1
Taille et offsets du pointer
scrw
rs.w
1
Largeur de l'écran en octets
scrH
rs.w
1
Hauteur de l'écran
scrD
rs.w
1
Profondeur de l'écran
scrC
rs.w
1
Nombre de couleurs
VARSIZE
rs.w
0
Start
lea VARS(pc)
,a5
movem.l aO dO,args(a5)
; ***** vérifie si Screensaver est déjà chargé lea port_id(pc),al EXEC FindPort tst.l dû
beq.s Install ; pas encore, donc en s'installe
irovea.l dO,aO ; si oui, on lui signale de quitter movea. 1 MP_SIGTASX(aO), al move.l SIGBREAKF_CIRL_C,dO EXEC Signal
moveq RETORN_OK,dO ; et c'est tout, rts
. ••••• installation
Install moveq RETURN_FAIL, d7
lea intname(pc) ,al ; ouvre l'intuition.library
moveq REV,dO
EXEC OpenLibrary
move.l dO,Int3ase(a5)
beq Nolnt
lea dosname(pc) ,al ; ouvre la dos.library
moveq REV,dO
EXEC OpenLibrary
move.l dO,Dos3ase(a5)
beq NoDos
DOS Output move.l dO,dl move.l Hello,d2 moveq HellLen,d3 DOS Write
suba.l al,al ; où suis-je ?
EXEC FindTask move.l dO,myTask(a5)
lea port_id(pc) ,a0 ; crée un MsgPort
moveq 0,d0
bsr CreatePort
move.l dO,myPort(a5)
beq NoPort
movea.Id0,a0 ; crée un bloc 10 moveq IOSTD_SIZE,dO bsr CreateExtIO move.l dO,myIO(a5) beq NoIO
lea idname(pc),aO ; ouvre l'input.device
movea.1 dO,al
moveq 0,d0
moveq 0,dl
EXEC CpenDevice
tst.l dO
bne NODev
moveq -l,dO ; alloue un signal
EXEC AllocSignal
move.b dO,iffsig(a5)
tmi NoSig
moveq l,dl
lsl.l dO,dl
move.l dl,iffMsk(a5) ; et calcule son masque
movea. 1 mylO(aS),al ; ajoute le handler à la chaîne
move.l myInter,IO_DATA(al)
move.w OJD_ADOHANDLER, IO_CCMMAND(al)
EXEC DoIO
. ..... Boucle principale
TheLoop move.l iffMsk(a5),dO ; il suffira d'un signe... bset SIGBREAKB_CTRL_C,dO EXEC Wait
st busy(a5) ; Qu'on ne me dérange pas !
Btst SIGBREAKB_CTRL_C,dO ; c'est la fin ? Tne Ciao ; oui, on s'barre
; Routine de sauvegarde de l'écran ScreenSave:
movea. 1 IntBase(a5) ,a3 ; repère l'écran de front movea. 1 ib_FirstScreen ( a3 ), a3 lea sc_3itMap(a3),a4
movea.1 lntBase(a5) ,aO ; change le pointeur actif
movea. 1 ib_Act iveWindow ( aO >, aO
move.l a0,windcw(a5)
move.1 wd_Pointer(aO),pointer(a5)
move.l wd_PtrHeight(aO) ,ptrsize(a5)
lea nyPointer,al ; Zzzz___
movem.l (al)+,dO-d3 INT SetPointer
move.l ss_file,dl; ouvre le fichier de sauvegarde move.1 MDDE_NEW?rLE,02 DOS Open
move.l dO,filehd(a5)
tne.s FileOK ; quelque chose a cloché...
movea. 1 a3,a0 ; on l'indique par un Beep
IOT DisplayBeep ; et on restaure le pointeur bra SaveEnd ; de la fenêtre active
; ***** Le fichier est ouvert. On peut ccrnnencer la sauvegarde FileOK move.w btn_BytesPerRow(a4) ,sczW(a5) ; largeur move.w tm_Rows(a4),scrK(a5) ; Hauteur
move.b hm_Depth(a4), scrD+l(a5) ; Profondeur
moveq l,dO move.w scrD(a5),dl lsl.l dl,dO
move.w dO,scrC(a5) ; Nb. Caileors
. ..... Ecrit le header iff "FORKxxxxTTÆM" (12 octets) WriteFORM:
lea theFORM(pc) ,aO ; voir article pour le détail du
moveq 60,dO ; "calcul” de la taille du fichier
move.w scrW(a5),dl
mulu scrH(a5),dl
mulu scrD(a5),dl; taille du BODY
add.l dl,dO
move.w scrC(a5),dl
mulu 3,dl ; taille du CMAP
add.l dl,dO
move.l d0,4(a0) ; Longueur de la FORM
move.l filehd(aS),dl move.l a0,d2 moveq 12,d3 DOS Write
; ***** Ecrit le chunk BHHD (20 octets + "HMHDxxxx")
WriteBHHD:
lea theBMHD (pc ), aO
move.l
tahd_SIZEOF,4(aO) ; Longueur du 3MKD
subq.w
l,d5 ; une par une, plan par plan
3QDY_1
move.w
scrD(a5),d4
move.w
scrW(a5),dO ; Largeur de l'image
subq.w
l,d4
lSl .Vf
3,d0 ; *8 pour nb. Pixels
lea
fcm_Planes(a4),a2
move.w
scrH(a5),dl ; hauteur
30DY_2
move.l
filehd(a5),dl
move.l
(a2)+,d2
move .vf
d0,8-tchd_w(a0)
add.l
d7,d2
move.vf
dl, 8 +ktEhd_h ( aO )
move.l
d6,d3
clr.w
8*tirid_x(a0)
DOS
Write
clr.w
8+tahd_y(aO)
dbra
d4,30DY_2
move.b
scrD-1 ( a5 ), 8-t-tahd_nPlar.es ( aO )
add.l
c6,d7
clr.b
8 +bmhd_Kasking(aO)
dbra
d5,BODY_l
clr.b
8+tcihd_Ccnçression(aO) ;
Pas de compression !
Clr.b
8+kchd_padl(aO)
Ferme le
fichier
clr.w
8+fcmhd_transparentColor(aO)
move.l
filehd(a5>,dl
move.b
$ 01,8+bmhd_xAspect(a0) ;
pas vraiment ça...
DOS
Close
move.b
$ 01,8+kxchd_yAspect(aO)
move.w
dO,8+tchd_pageWidth(aO)
Restaure
le pointeur de souris original
move.w
dl, 8+htnhd_pageHeight(aO)
SaveSnd
movea.l
windcw(a5) ,a0
move.l
pointer(a5) ,d0
move.l
£ilehd(a5) ,dl
beq.s
NcMouse
move.l
a0,d2
movea.l
d0,al
moveq
kmhd_SIZEOF+8, d3
moveq
0,d0
DOS
Write
moveq
0,dl
moveq
0,d2
; ***** Ecrit le
chunk CNAP ((3*nb. Couleurs) octets + "CMAPxxxx")
moveq
0,d3
WriteCKAP:
move.b
ptrsize+0(a5),d0 ; pourquoi ce sont des
lea
theCMAP (pc ), aO
move.b
ptrsize+l(a5),dl ; octets, hein, pourquoi ?
Mcvea.l
sc_ViewPort+vp_ColorMap(a3),al
move.b
ptrsize+2(a5),d2
movea.l
cm_ColorTable(al),a1 ;
table des couleurs
move.b
ptrsize+3(a5),d3 ; pourquoi tant de haine ?
Move.w
scrC(a5),d0
D7T
SetPointer
mulu
3,d0
bra.s
Again
move. 1
d0,4(aO)
Noîtouse
htt
ClearPointer
lea
8(a0),a2
move.w
scrC(a5),Ô2
Again
sf
busy(a5) ; on peut à nouveau être signalé
subq.w
l,d2
bra
TheLoop ; boucle sur WaitO
CMAPlp move.w
(al)+,d0 ; Valeur RGB
move.w
d0,dl
. ••••••
lsr.w
4,dl
; Pin du programme
. Libère et ferme tout.
Anrii.b
$ fO,dl
Ciao
moveq
RETORN_OK,d7
move.b
dl,(a2)+ ; Composante Rouge
move.w
d0,dl
Exit
movea.1
myIO(a5),al ; enlève le hardier de la chaîne
andi.b
$ f0,dl
move.l
mylnter,IO_DATA(al)
move.b
dl,(a2>+ ; Conposante Verte
move.w
mD_R£MHANDLSR, IO_CO-24AND(al)
lsl.b
4,d0
2XEC
DoIO
move.b
dO,(a2)+ ; Conposante Bleue
dbra
d2,CMAPlp
moveq
0,d0 ; libère le signal
move.b
iffSig(a5),d0
move.l
filehd(a5),dl
EXZC
FreeSignal
move.l
a0,d2
move.l
4(a0),d3
NoSig
movea.l
myIO(a5),al ; ferme l'input.device
addq.l
8,d3
EXEC
CloseDevice
DOS
Write
NoDev
movea.l
myIO(a5) ,a0 ; détruit le bloc IO
; ***** Ecrit le
chunk CAMG "CAMG0004xxxx" (12 octets)
bsr
DeleteExtIO
WriteCAMG:
lea
theCAMG(pc),a0
NoIO
movea.l
myPort(a5),a0 ; détruit le MsgPort
move.l
$ 00000004,4(aO) ; Longueur du CAM3
bsr
DeletePort
move.w
sc ViewPort+vp_»odes(a3),d0
andi.l
CAMGKSK,dO ; Masque certains bits
NoPort
movea.l
DosBase(a5),al ; ferme la dos.library
move.l
dO,8(a0)
EXEC
CloseLibrary
move.l
£ilehd(a5),dl
îfoDOS
movea.l
XntBase(a5),al ; ferme l'intuition.library
move.l
a0,d2
EXEC
CloseLibrary
moveq
12,d3
DOS
Write
Nolnt
move.l
d7,d0 ; code d'erre-ur dans dO
rts
; et retour au CLI
; ***** Ecrit le
chunk SODY ((h*l*p) octets + "BODYxxxx")
Write30DY:
; ******
lea
theBODY(pc),aO
; Routines tirées d’Amiga.Lib
move.w
scrW(a5),d0
mulu
scrH(a5),d0
. *****
Port=CreatePort(Marne,Pri)
rnulu
scrD(a5),d0
CreatePort:
move.l
dO,4(aO)
movem.l
d2-d7 a2 a6,-(sp)
move.l
a0,d7 ; d7=name
move.l
filehd(a5),dl
move.b
d0,d6 ; d6=pri
move.l
a0,d2
moveq
-l,d0
moveq
8,d3
CALLEXEC
AllocSignal
DOS
Write
cnpi.b
-l,dO
keie.s
- SigOk
moveq
0,d7
.NoSig
moveq
0,d0
move.w
scii-î(a5) ,q6
bra.s
.C?_Ret
ext.l
d6
.SigOk
move.l
d0,d5 ; d5=SigBit
moveq
$ 22,dO ; sizeof(struct MsgPort)
move.w
scrH(a5),d5 ; Ecrit les lignes de l'image
move.l
$ 10001,dl ; MEMF_?DBLIC 1KEMF. CLEAR
dcb.b VARSizs,0
VARS
is. Node. Ln_Succ, i s_Node.ln_Type, is_Node.In Narne is_Data nylnputHandler ; is_Code
is_Node.ln_Pred is_Node.ln_Pri
"intuition.library",0 "dos.library",0 "input.device",0,0
dc. b "Screensaver vl.O installé",$ 0a 1991 par Max pour l'ANTn,$ 0a
0,0 ; $ 0000 $ 0600, $ 7FF0, $ 7FFC, $ 1FF8, $ 0FC0, $ 00E0, $ 0000
S0F40,$ 0F40,$ 3FE0,$ 3FE0 $ 7BF8,$ 7FF8,$ F7F8,$ FFF8 $ 3FDE,$ 3FFE,$ 7FBC,$ 7FFC, $ 07F0, $ 07F0, $ 01C0, $ 01C0. $ 0680,$ 0680,$ 0000,$ 0000. $ 0040,$ 0040,$ 0000,$ 0000.
$ 7FE0,$ 7FE0 $ 6lFC,$ 7FFC $ 3F0C,$ 3FFC $ 0700,$ 0700 $ 00C0,$ 00C0 $ 0000,$ 0000
CALLEXEC AllocMem move.l d0,d4 ; d4=port
br.e. s . PortOk
.NoPort xnove.1 d5, dO CALLEXEC FreeSignal moveq 0,d0 bra. S .CP_Ret . PortOk move .1 d4, a2
move.l d7,KP+I2I NAME(a2) move.b d6,K?+I2J_PRI(a2) move. B NT_KSGPORT, MP+LK TYPE ( a2 ) move.b PA_SIGNAL,MP_FLAGS(a2) move.b d5,MP_SIGBIT(a2) suba.l al,al CALLEXEC FindTask move.l dO,MP_SIGTASK(a2) tst.1 d7 beq.s .List move.l a2,al CALLEXEC AddPort bra. S .CP_Ok . List lea MP_MSGLIST ( a2 ), al
NEWLIST al .CP_Ok move.l a2,d0 .CP_Ret movem.l (sp)+,d2-d7 a2 a6 rts
. ..... void DeletePort(port)
DeletePort:
movem.l d2-d7 a2 a6, - (sp) move.l a0,a2 tst.l MP.m_NAME ( a2 ) beq.s .NoName move.l a2,al CALLEXEC RemPort .NoName moveq -l,dO
move.l dO,MP_SIGTASK(a2)
move.l dO,MP_MSGLIST+IH_HEAD(a2)
moveq 0,d0
move.b MP_SIGBIT(a2),dO
CALLEXEC FreeSignal
move.1 a2, al
moveq $ 22,dO
CALLEXEC FreeMem
movem.l (sp)+,d2-d7 a2 a6
rts
. ..... iORequest =CreateExt 10 (Port, Size) CreateSxtIO:
movem.l d2-d7 a2 a6,-(sp) move.l d0,d6 ; d6=Size move.l a0,d7 ; d7=Port bue. S .PortOk .NoPort moveq 0,d0 bra.s .CE_Ret .PortOk move. 1 d6,d0 move.l $ 10001,dl
CALLEXEC AllocMem tst.1 dO taie. S . ÏO__Ok .NoIO moveq 0,d0 bra. S .CE_Ret .IO_Ok move.l d0,a2
move.b OT_MESSAGE,IO+MP+LN_TYPE(a2) move.w d6, IO+KP+MN_LENGTH(a2) move.1 d7,IO+MP+MN_REPLYPORT(a2) nove.l a2,d0 .CE_Ret movem.l (sp)+,d2-d7 a2 a6 rts
. ....«void DeleteExtIO(lORequest) DeleteExtIO:
movem.l d2-d7 a2 a6,-(sp) moveq -l,dO
move.b dû,IO.MP+LN_TYPE(aO) move.1 dO,IO+MP+MN_REPLYPORT(aO) move.1 dO,I0_DEVTCE(aO) moveq 0,d0
move.w IO+MP+MN_LENGTH(aO), dO move.l aO,al CALLEXEC FreeMem moven.l (sp)+,d2-d7 a2 a6 rts
.Signal move. 1 a0,-(sp) ; sauve aO
move.l iffKsk(al),d0 movea.l myTask(al),al EXEC Signal ; envoie le signal movea.l (sp)+,a0 ; récupère aO
movea.l ie_NextSvent(aO),aO ; saute cet événement
.Rien move.l a0,d0 rts
; et le signale au programme principal le cas échéant. ; Rappel : al contient is_Data, soit nos variables myInputKandler:
tst.b tusy(al) ; sauf si on est déjà en train bne.s .Rien ; de sauver
cmpi.b IECLASS_RAWKEY,ie_Class(aO) bne.s .Rien ; c'est pas le clavier
.MayBe move.w ie_Qualifier(aO),d0
andi.w
QUAIMSK,d0 ;
masque le
code
empi .w
QOAU4SK,dO ;
CTRL LALT RALT ?
Beq.s
.Signal
ampi.w
QüALl,d0 ;
CTRL LALT
7
beq.s
.Signal
empi .w
QUAL2,dO ;
CTRL RALT
7
bne.s
.Rien
theFORM de. 1 "FQRM",0, "IL3M"
theBMHD de. 1 "HVHD",0
dcb.b bmhd_SIZSOF theCMAP de. 1 "CMAP", 0
dcb.b (64*3) ; place pour 64 couleurs theCAMG de. 1 "CAM3",0,0
the30DY dc.l "BODY-.O
* ***********************************
Définition du pointeur indiquant la sauvegarde Doit de trouver en CHIP-RAM ! Section PointerDefs, DATA_C
myPointer:
dc. l 24,16,
dc. w $ 0000, de.w $ 0600,
dc. w $ 61F0,
dc. w $ 7F0C,
dc. w $ 1FF8,
dc. w $ 0FC0,
dc. w $ 00E0,
dc. w $ 0000,
cmpi.w $ 46,ie_Code(aO) ; DEL ? Bne.s .Rien
Hello
dc. b .
HellLen EQO *-Hello even
imylnterdc.l 0,0
dc. b 0,101
dc. l hndl_id
dc. l VARS
Height, width, Xoffset, Yoffset
espace des variables
touches spéciales
dc. l
intname dc.b dosname de. B idname dc.b
port_iddc.b " Screensaver. Port ", 0,0
hndl_iddc.b "Screensaver.InputHandler",0,0 ss_filedc.b " ram: Screensaver, image ",0
; InputKandler. Vérifie si CTRL ALT DSL est pressé
Par MAX
Voici la fin de notre étude des instructions du 68000. Reportez- vous aux deux précédents numéros de VANTpour plus de détails sur la manière de lire les tableaux.
Le68000de AàZ
RESET (remise à 0 des circuits externes)
Instruction privilégiée Syntaxe RESET Taille - Format S4E70 Flags Inchangés
Le mois prochain (et non ce mois-ci comme annoncé un peu vite dans notre dernier numéro...), nous entamerons une petite mais courte série sur futilité et l'utilisation de certaines instructions obscures du 68000. Comme LINK. CHK. RTR ou encore DBPL. Mais ceci est une autre histoire...
OR (ou logique)
Syntaxe OR ea>, Dn OR Dn, ea>
Taille Octet, rot, rot long
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1000 REGISTRE OP-MQDE ADRESSE EFFECTIVE
OP-M3DE : Octet Mot Long
000 001 010 (syntaxe 1)
100 101 110 (syntaxe 2)
N : 1 si résultat négatif, 0 sinon
Z : 1 si résultat cul, 0 sinon
V : toujours 0 C : toujours 0 X : inchangé
ORI (ou logique immédiat)
Syntaxe ORI Sdonr.ée, ea>
Taille Octet, rot, rot long
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
00000000 TAILLE ADRESSE EFFECTIVE
TAILLE : 00=octet, 01-œot, 10=rot long
La donnée est codée dans le rot (TAXLLB=00 ou 01) eu dans le rot long (TAXLLE=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 : toujours 0 C : toujours 0 X : inchangé
ORI to CCR (ou logique immédiat avec CCR)
Syntaxe ORI Sdonnée, CCR Taille Octet
Ffcrmat 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0000000000111100
La donnée (8 bits) est codée dans le rot suivant le code opératoire.
Flags N : 1 si le bit 3 de la donnée est 1, Inchangé sinon
Z : 1 si le bit 2 de la donnée est 1, inchangé sinon
V : 1 si le bit 1 de la donnée est 1, inchangé sinon
C : 1 si le bit 0 de la donnée est 1, inchangé sinon
X : 1 si le bit 4 de la donnée est 1, inchangé sinon
ORI to SR (ou logique immédiat avec SR)
Instruction privilégiée Syntaxe ORI Sdonnée,SR Taille Mot
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0000000001111100
La donnée (16 bits) est codée dans le rot suivant le code opératoire.
Flags N : 1 si le bit 3 de la donnée est 1, inchangé sinon
Z : 1 si le bit 2 de la donnée est 1, inchangé sinon
V : 1 si le bit 1 de la donnée est 1, inchangé sinon
C : 1 si le bit 0 de la donnée est 1, inchangé sinon
X : 1 si le bit 4 de la donnée est 1, inchangé sinon
PEA (empilement d’une adresse effective)
Syntaxe PEA ea>
Taille Mot long
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 010010000 1 ADRESSE EFFECTIVE
Flags Inchangés
Rx : numéro du registre source (0-7)
ROL, ROR (rotation)
Syntaxe Rox Dx, Dy
Rox donnée,Dy Rox ea>
X=L (Left, gauche) ou R (Right, droite)
Format Décalage d'un registre :
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1110 NOMBRE D TAILLE I 1 1 REGISTRE
Décalage d'une adresse :
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1110011D11 ADRESSE EFFECTIVE
ïOEBE : rartare de décalages ou nrréo du registre de Serrées le contenant (0-7)
D : 0=décalage à gauche, l=décalage à droite
TAILLE : 00=octet, 01=rot, 10=rot long
I : 0=NCMBRE contient le nanbre de décalages (0-7, 0=8)
1=NCM3RE indique le registre contenant le nombre de décalages (rodnlo 64)
Flags N : 1 si résultat négatif, 0 sinon Z : 1 si résultat nul, 0 sinon V : toujours 0
C : 1 si le dernier bit sorti de l'opérande était 1 X : idem C
ROXL, ROXR (rotation avec X)
Syntaxe ROXx Dx, Dy
ROXx sdonr.ée, Dy
ROXx ea>
x=L (Left, gauche)
ou R (Right, droite)
Format Décalage d'un registre :
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1110 NOMBRE D TAILLE I 1 0 REGISTRE
Décalage d'une adresse :
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1110010D11 ADRESSE EFFECTIVE
NOMBRE : nombre de décalages ou numéro du registre de données le contenant (0-7)
D : 0=décalage à droite, l=décalage à gauche
TAILLE : 00=octet, 01=rot, 10=rot long
1 : 0=NCMBRE contient le nombre de décalages (0-7, 0=8)
1=NCMBRE indique le registre contenant le nombre de décalages (rodulo 64)
Flags N : 1 si résultat négatif, 0 sinon Z : 1 si résultat nul, 0 sinon V : toujours 0
C : 1 si le dernier bit sorti de l'opérande était 1 X : idem C
RTE (retour d’exception)
Syntaxe RTE Taille - Format S4E73
Flags Positionnés d'après le rot dépilé
RTR (retour et restitution de CCR)
Syntaxe RTR Taille - Format 54B77
Flags Positionnés d'après le rot dépilé
Note CCR doit avoir été empilé avant JSR ou BSR
RTS (retour de sous-routine)
Syntaxe RTS Taille - Format S4E75 Flags Inchangés
SBCD (soustraction décimale avec le bit d’extension)
Syntaxe SBCD Dy, Dx SBCD -(Ay),-(Ax)
Taille Octet
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1000 Rx 10000M Ry
Ry : numéro du registre destination (0-7) -ïÇSSSjE»
(fin)
M : Mode (0=registres de données, l=registres d'adresse)
Flags N : indéfini
Z : 0 si résultat non-nul, inchangé sinon V : indéfini
C : 1 si retenue, 0 sine»
Scc (positionnement conditionnel)
Syntaxe Scc ea>
Taille Octet
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0101 CONDITION 1 1 ADRESSE EFFECTIVE
Flags Inchangés
STOP (arrêt du processeur)
Syntaxe STOP donnée Taille - Format $ 4E72
La donnée (16 bits) est codée dans le mot suivant le code opératoire Flags Positionnés selon la donnée imédiate.
Note La donnée est chargée dans SR et le processeur passe en état arrêté jusqu'à ce qu'une exception TRACE, une interruption ou un RESBT survienne
SUB (soustraction binaire)
Syntaxe SUB ea>,Dn SüB Dn, ea>
Taille Octet, mot, mot long
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1001 REGISTRE OP-MODE ADRESSE EFFECTIVE
Format
SÜBX -(Ay),-(Ax)
Taille Octet, mot, mot long
Fonnat 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
10 0 1 Rx 1 tatt.tr 0 0 M Ry
Rx : registre source Ry : registre destination
M : 0=registres de données, l=registres d'adresse
Flags N : 1 si résultat négatif, 0 sincp
Z : 0 si résultat non-nul, inchangé sinon
V : 1 si débordement, 0 sinon C : 1 si retenue, 0 sinon
X : idem C
SWAP (échange des mots)
Syntaxe SWAP Dn Taille -
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0100100001000 REGISTRE
REGISTRE : numéro du registre de données (0-7)
Flags N : 1 si résultat négatif, 0 sinon
Z : 1 si résultat nul, 0 sinon
V : toujours 0 C : toujours 0 X : inchangé
TAS (test et positionnement)
Syntaxe TAS ea>
Taille Octet
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0100101011 ADRESSE EFFECTIVE
OP-MODE : Octet Mot Long
000 001 010 (syntaxe 1)
100 101 110 (syntaxe 2)
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
SUBA (soustraction binaire d’un registre d’adresse)
Syntaxe SüBA ea>,An Taille Mot, mot long
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 1001 REGISTRE OP-MODE ADRESSE EFFECTIVE
Format
OP-MODE : 011=xnot, lll=mot long Flags Inchangés
SUBI (soustraction binaire immédiate)
Syntaxe SOBI 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
00000100 TAILLE ADRESSE EFFECTIVE
TAILLE : 00=octet, 01=mot, 10=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 : idem C
SUBQ (soustraction binaire immédiate rapide)
Syntaxe SUBQ «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
0101 DONNEE 0 TAILLE ADRESSE EFFECTIVE
DONNES : donnée immédiate sur 8 bits TAILLE : 00=octet, 01=mot, 10=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 : idem C
SUBX (soustraction avec le bit d’extension)
par LOÏC FAR
Syntaxe SUBX Dy, Dx
Flags N : 1 si résultat négatif, 0 sine»
Z : 1 si résultat nul, 0 sinon V : toujours 0 C : toujours 0
TRAP (instruction TRAP)
Syntaxe TRAP feuméro Taille -
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 010011100100 NUMERO
NUMERO : numéro de 1'exception TRAP à déclencher (0-15)
Flags Inchangés
TRAPV (instruction TRAP)
Syntaxe TRAPV Taille - Format $ 4E76 Flags Inchangés
TST (test)
Syntaxe TST ea>
Taille Octet, mot, mot long
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 01001010 TAILLE ADRESSE EFFECTIVE
TAILLE : 00=octet, 01=mot, 10=mot long
Flags N : 1 si résultat négatif, 0 sinon Z : 1 si résultat nul, 0 sinon V : toujours 0 C : toujours 0 X : inchangé
UNLK (libération de liens)
Syntaxe UNLK An Taille -
Format 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0100111001011 REGISTRB
REGISTRE : numéro du registre d'adresse (0-7)
Flags Inchangés
La première partie de cet article va donc consister en une description des menus : comment les créer et comment les gérer. Un programme d'exemple constituant la seconde partie mettra en pratique toute cette théorie. Dernier point avant que de commencer : les termes anglais entre parenthèses dissiminés tout au long de cet article, sont les termes "officiels" que vous trouverez dans la documentation développeur de Commodore, ceci afin de permettre à ceux qui la possèdent, de s'y retrouver plus facilement.
DEFINITION ET ACCES
NextMenu : pointeur sur le menu suivant dans la liste. Lorsqu'il s'agit du dernier menu de la barre. NextMenu doit être initialisé à NULL.
LeftEdge, TopEdge, Width, Height : taille de la boite de sélection du menu. LeftEdge représente la position de la boite relativement à celle de l'écran. Width représente sa largeur. TopEdge et Height ne servent pas dans la version actuelle d'intuition, plus tard peurêtre (pour le moment on les met à 0 et on en parle plus).
Flags : peuvent être fixé par le programme et par Intuition. Ce sont : MENUENABLED : indique si le menu est ou non sélectionnable. Si ce flag n'est pas présent lorsque l'on soumet le menu à Intuition, il n'est pas sélectionnable (de même que les options qui l'accompagnent). Il est possible d'autoriser ou non l'accès à un menu en cours de programme à l'aide des fonctions OnMenu() et OffMenu().
MIDRAWN : positionné par Intuition lorsque le menu est affiché.
MenuName : pointeur sur une chaine de caractères (terminée par un '0') qui représente l'intitulé du menu. Intuition affichera ce texte dans la boite de sélection du menu.
Firstltem : pointeur sur la première option du menu qui est une structure Menultem.
Pour activer un menu Intuition, l'utilisateur doit appuyer sur le bouton droit de la souris. Intuition affiche alors la barre de menus (menu strip) liée à la fenêtre active, en haut de l'écran. Elle est composée d'un certain nombre de mots, baptisés "intitulés" ou "titres” des menus.
Quand l'utilisateur positionne le pointeur de la souris sur un menu, il le sélectionne : le titre du menu apparaît alors en surbrillance et une boîte contenant les différentes options qu'il propose (menu items) apparaît juste en dessous. La largeur de cette boîte est indépendante de celle du titre du menu. Sa hauteur dépend quant à elle du nombre d'options dans le menu et de leur hauteur. Lorsque l'utilisateur sélectionne une option (toujours à l'aide du pointeur de la souris), celle-ci apparait à son tour en surbrillance. La confirmation de la sélection se fait tout simplement en relâchant le bouton droit de la souris, l'option choisie étant toujours en surbrillance. Une option de menu peut faire apparaître un sous-menu (sub-menu) présentant lui-même d'autres options.
HIERARCHIE
La description ci-dessus, bien qu'un peu fastidieuse, nous permet d'appréhender la hiérarchie au sein des menus. En effet, on voit que l'on peut lier X menus à une fenêtre, chacun pouvant contenir Y options, pouvant elles-même contenir Z sous-options. Chaque entité de même niveau est liée à la suivante par une liste chaînée simple.
INITIALISATION
Lorsque l'on veut gérer des menus, il faut d'abord les penser. On dessine sur papier la structure des menus, comprenant toutes les entités associées en partant des sous-options, puis les options, et en finissant par les menus. A noter que divers utilitaires du domaine public ou du commerce permettent de simplifier cette tâche. Leur principale caractéristique est de produire un code source C ou assembleur que le programmeur n'aura plus qu'à inclure dans son projet. Le plus célèbre est PowerWindows de je-ne-sais-plus-qui-mais- ce-n'est-pas-du-domaine-public.
STRUCTURE D’UN MENU
Comme toujours dans f Amiga. Un menu (comprenez "un titre de menu") est défini par une structure C. que voici :
struct Menu
struct Menu «NextMenu;
SHORT LeftEdge,TopEdge,Width,Height;
USHORT Flags;
UBYTE «MenuName;
struct Menultem «Firstltem;
};
Les différents champs de cette structure sont décrits ci-après.
STRUCTURE D’UNE OPTION
La structure C associée aux fonctions et sous-fonctions est la même, mais elle ne s'utilise pas de la même manière. Cette structure est la suivante.
Struct Menultem
struct Menultem «Nextltem;
SHORT LeftEdge, TopEdge, Width, Height;
USHORT Flags;
APTR ItemFill;
BYTE Ccmnand;
struct Menultem «Subltem;
USHORT NextSelect;
};
Nextltem : pointeur sur la fonction suivante dans la liste chaînée. Le dernier élément dans la liste doit être initialisé à NULL.
LeftEdge, TopEdge, Width, Height : taille et position de la boite de sélection de l'option (zone dans laquelle l'option est sélectionnée par le pointeur de souris). LeftEdge et TopEdge représentent la position relative du coin haut-gauche de la boîte par rapport à la position du coin haut-gauche de celle du menu. Width et Height représentent respectivement la largeur et la hauteur de la boîte.
Flags : positionnée par le programme ou par Intuition. Ce sont :
CHECKIT : place un CheckMark devant l'option lorsqu'elle est sélectionnée (interrupteur on off). La structure NewWindow de la fenêtre à laquelle le menu est associée, contient un champ nommé CheckMark pouvant pointer sur une imagerie personnelle pour le checkmark.
CHECKED : si CHECKIT est positionné. CHECKED rend l'option active (on) dès la mise en place du menu.
ITEMTEXT : mis à 1 si l'option de menu est un texte, à 0 si c'est une image.
COMMSEQ : mis à 1 si l'option peut également être sélectionnée au clavier (Amiga droite + une touche). Le code ASCII de cette touche se trouve alors dans le champ Command (voir ci-dessous).
ITEMENABLED : mis à 1 l'option est sélectionnable. Sinon elle apparaît en grisé. Il est possible d'autoriser ou d'interdire l’accès à une option en cours de programme à l'aide des fonctions OnMenuQ et OffMenu() que nous décrirons ultérieurement.
NOTE : Si une option devient non sélectionnable. Toutes les sous-options qui lui sont associées sont également inaccessibles.
HIGH Flags : indique le mode de surbrillance à appliquer à cette option. Il faut positionner un et un seul des bits ci-dessous.
HIGHCOMP : l'option sélectionnée apparaît en vidéo inversée (cas le plus fréquent).
NTUITION
HIGHBOX : traçage d'une boîte (rectangle) autour de la boite de sélection de l'option (souvent pour "Quit").
HIGHIMAGE : affichage d'un intitulé complémentaire (texte ou image).
HIGHNONE : aucune surbrillance, il n'y pas de différence entre l'intitulé
sélectionné ou non.
Les flags suivant sont positionnés plus particulièrement par Intuition.
ISDRANVN : mis à 1 quand le sous-menu associé à cette option est affiché.
HIGH1TEM : mis à 1 lorsque l'option est actuellement affichée en surbrillance.
MutualExciude : là. De plus amples explications me semblent nécessaires. Vous pouvez choisir d'avoir certaines options, déclarées avec le flag CHECKIT qui. Sélectionnées, dé-sélectionnent d'autres options. C'est ce que l'on appelle l'exclusion mutuelle. Prenons un exemple porté sur la boisson. Un personnage a la possiblité de choisir d'emporter à boire dans quatre types de contenants : une fiole, une bouteille, un bidon ou un tonneau. Il est raisonnable de penser que le personnage choisissant le tonneau ne pourra pas emporter en plus une bouteille ou un bidon. La fiole, elle, peut toujours se glisser dans une poche. Par contre il pourra très bien prendre le bidon, la bouteille et la fiole en même temps (les camarades de l'ANT y arrivent sans problème). Cela signifie que la possession du tonneau exclut la bouteille et le bidon, de même que la possession du bidon ou de la bouteille (à fortiori des deux) exclut le tonneau.
Le champ MutualExclusion est un mot long (type LONG sur 32 bits) où chaque bit représente une option dans la liste correspondant a un menu. Le premier dans la liste a le bit 0. Le second le bit 1. Etc. Ce qui signifie dans un premier temps que seuls 32 options appartenant à un même menu peuvent utiliser ce champ (ce qui n'est déjà pas si mal !). Lorsque le Nième bit du champ MutualExciude de l'option X est positionné, l'option N est automatiquement exclue lorsque l'option X est sélectionnée. Dans notre exemple, on va mettre Sfft'6 pour tonneau (on exclut tous les autres sauf la fiole et lui). Pour le bidon et la bouteille, on met S0001 car on exclut le tonneau seulement Pour la fiole on mettra S0000 car on n'exclut rien du tout.
ItemFill : pointeur sur l'intitulé de la fonction, en l'occurence une structure IntuiText si le flag ITEMTEXT est positionné, sinon c'est une structure Image.
SelectFill : si le flag HIGHIMAGE est positionné. Intuition substituera à la structure contenue dans ItemFill celle contenue dans SelectFill lorsque l'option sera sélectionnée. SelectFill est donc un pointeur sur une structure IntuiText ou Image, selon la présence ou non du flag ITEMTEXT.
NOTE : on ne peut pas afficher une image à la place d'un texte, et vice-verça.
Command : code ASCII du caractère composant le racourci-clavier lorsque le flag COMMSEQ est positionné. L'utilisateur peut choisir directement F option en appuyant simultanément sur la touche Amiga droite et sur le caractère contenu dans ce champ. Au niveau programme proprement dit. Tout
se passe comme si la fonction avait été sélectionnée à la souris.
NOTE : aucune vérification n'est faite pour voir si une même commande est utilisée plusieurs fois dans un menu. De plus. Intuition ne fait pas la différence entre les majuscules et minuscules ; s'il en a besoin, le programme doit tester lui-même si une touche Shift (ou Caps Lock) est enfoncée au moyen du champ Qualifier de la structure IntuiMessage (cf. Plus loin).
Subltem : pointeur sur la première sous-option ce cette option. Ce champ est ignoré si l'option courante fait déjà partie d'un sous-menu.
NextSelect : dernier champ de la structure, mais il est loin d'être le moins important. En effet, si l'utilisateur a la possibilité de sélectionner plusieurs options dans un menu en une seule opération (en cliquant avec le bouton de gauche de la souris les différentes options, tout en maintenant le bouton droit de la souris appuyé), rien dans l'IntuiMessage n'indique au programme que c'est bel et bien ce qui s'est passé. Pour garder une trace de cette sélection multiple et donc permettre de traiter toutes les options choisies. Intuition remplit le champ NextSelect avec le numéro de l'option suivante. Bon allez, je suis compréhensif et vous livre un petit bout de source qui illustre la manière de s'v prendre.
Wfaile (sélection != MENUNULL)
option = ItemAdress(menu, sélection);
* traitement de l'option *
* récupération de l'adresse de l'option suivante* sélection = option->NextSelect;
}
Pas trop difficle ?
MISE EN PLACE DU MENU
On a donc décrit la structure de son petit menu, en suivant les explications ci-dessus et en s'imprégnant de l'exemple ci-dessous (le va et vient est terminé, on continue).
Première opération à réaliser, ouvrir une fenêtre à l'aide de la fonction OpenWindow(). En effet, pour attacher un menu à une fenêtre, il semble raisonnable d'ouvrir une fenêtre (si. Si, j'vous jure !). Comme déjà dit plus haut, le champ CheckMark de la structure NewWindow peut pointer sur une structure Image décrivant un checkmark personnel à utiliser pour TOUTES les options du menu ayant les flags CHECKIT et CHECKED positionnés. Ensuite, on attache le menu à la fenêtre, à l'aide de la fonction SetMenuStripO.
SetMenuStrip(fenêtre, menu)
- fenêtre est un pointeur sur une structure Window créée par OpenWindow(). Il s'agit de la fenêtre à laquelle on veut attacher le menu.
- menu est un pointeur sur le premier menu de la liste chainée des menus à afficher.
Bien entendu, il ne se passe rien de particulier lorsque l'utilisateur sélectionne une option du menu. C'est au programme de réagir en conséquence. Il faut donc écrire un petit bout de code pour savoir ce que l'utilisateur a sélectionné et quelle fonction activer. Pour ce faire, on va encore se faire aider par Intuition (brave petite).
A chaque fois que l'utilisateur active le système de gestion de menus en pressant le bouton droit de la souris. Intuition génère un message (sous la forme d'une structure IntuiMessage) de classe MENUPICK. Vous pouvez donc tester les messages que vous envoie Intuition pour savoir si oui ou non il s'agit de 1‘activation d'un menu. Voici le résultat en quelques lignes.
Struct Window *fenetre; struct MsgPort *port; struct IntuiMessage *message;
ULONG classe_message;
UWORD codemessage, qual_message;
BOOL fini;
* initialisation diverses *
port = fenetre->OserPort;
* boucle d'attente * while((fini)
WaitPort(port);
message = (struct IntuiMessage *)GetMsg(port); while (message)
classe_message = message->Class; code_message = message->Code; qual_message = message->QuaIifier;
ReplyMessage(message); if (classe_message == MENUPICK)
* traitement de la fonction *
* récupération du message suivant * message = (struct IntuiMessage *)GetMsg(port);
)
}
Le programme fournit ci-dessous utilise ce principe.
Il nous faut maintenant déterminer quels menus, options, et sous-options ont été sélectionnés. Une fois de plus. Intuition nous aide (que ferait-on sans elle?). En effet, lorsqu'il envoie une structure IntuiMessage de classe MENUPICK. Celle-ci contient également dans son champ Code un WORD correspondant au menu, à l'option et éventuellement à la sous-option sélectionnée. Ce mot long étant assez peu parlant par lui-même, on va déterminer quelle option précisémment a été sélectionnée à l'aide des macros :
MENUNUM(Code) qui renv oie le numéro du menu sélectionné : ITEMMENU(Code) qui renvoie le numéro de la fonction sélectionnée : SUBNUM(Code) qui renvoie le numéro de la sous-fonction ;
Les numéros commencent toujours à zéro et non à un.
Si l'on active la fonction 2 du menu 4 on a :
MENUNUM(Code) = 3 ITEMNUM(Code) = 1 SUBNUM(Code) = NOSUB
Si l'on active la sous-fonction 3 de la fonction 4 du menu 1 on a :
MENUN U M( Code ) = 0 ITEMNUM(Code) = 3 SUBNUM(Code) = 2
Comme on peut le remarquer, lorsqu'aucune sous-option n'est sélectionnée. SUBNUMO renvoie NOSUB. De même, si aucune option n'est sélectionnée. ITEMNUMO renvoie NOITEM. Enfin, si aucun menu n’est sélectionné (on clique le bouton droit et on relâche en dehors de la zone des menus). MENUNUM() vaut NOMENU.
On notera qu'intuition envoie systématiquement un message MENUPICK lorsque 1 utilisateur a enfoncé le bouton droit de la souris, et ce même si aucune sélection n’a été effectuée. D'où l'utilité de vérifier que le champ Code soit différent de MENUNULL. Le programme d'exemple fournit une fonction testmenuO qui utilise ce principe.
Il ne nous reste plus qu'à étudier quelques fonctions qui permettent de travailler dynamiquement sur les menus et nous aurons fait le tour de cet outil si pratique.
FONCTIONS UTILES
Nous avons entrevu la possibilité qui nous était donnée d'interdire ou d'autoriser l'accès à un menu, une option ou une sous-option en plein milieu de l'exécution du programme.
L'interdiction est réalisée à l'aide de la fonction OffMenuO
OffMenu(fenetre, nnero)
- fenetre est un pointeur sur la fenêtre à laquelle est lié le menu.
- numéro correspond au numéro de la fonction ou du menu à interdire (sous une forme équivalente au champ Code de la structure IntuiMessage de tvpe MENUPICK que renvoie Intuition quand une fonction a été sélectionnée). On le calcule avec la formule numéro = muméro_sousfonction*2048 + numéro_fonction*32 + numero_menu. C'est tout simple et en plus ça fonctionne très bien.
Pour autoriser un menu à nouveau on utilise OnMenul ).
OnMenu ( f er.êt re, numéro )
Enfin la dernière fonction
IcemAddress (premier_menu, nuaero)
calcule l'adresse d'une option ou sous-option à partir de l'adresse du premier menu et du muméro associé au menu à la fonction ou la sous-fonction à autoriser.
Enfin, lorsque l'on n'a plus besoin du menu, on l'élimine de la fenêtre srâce à la fonction
ClearMenuStrip(fenetre)
fenetre étant le pointeur sur la fenêtre à laquelle est lié le menu.
CONCLUSION
Il ne vous reste plus qu'à étudier le programme fourni comme exemple et qui se trouve bien entendu sur la disquette d'accompagnement de ce numéro.
Il a été compilé sans problème avec le Lattice V 5.10 et l'Aztec V 5.0d
Le mois prochain, la gestion des sprites avec comme exemple quelques variations sur la gestion du pointeur de souris.
*
Les Menus sous Intuition programme réalisé par Herr Doktor Von Glutenstinmelimdorf (1991)
On ccmnence par déclarer les includes
V
ttinclude stdio.h>
include intuition intuition.h>
include intuition intuitionbase.h>
Kinclude exec types.h>
Kdefine HTTOITION REV 0L * dernière révision d'intuition *
déclaration des variables externes
* *************************************************
struct Window *OpenWindcw ();
struct Windcw *fenetrel = NULL;
struct Window *fenetre2 = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct intuiText itextl =
3,1,COMPLEMENT, * couleurs et mode d'écriture * 0,0, * position *
NULL, * fonte *
"Close", * pointeur vers le texte *
NULL * structure IntuiText suivante *
};
struct Menultem rrsenuitem2 =
NULL, * structure Menultem suivante*
0,9,80,8 * position et taille *
Itcïn'EXT+CCMMSEQ+ITEMENABLED+HIGHCCM?, * flags *
»**«•*•*•******•
0,
(APTR)&itextl,
HIGHCOMP,
'c' ,
NULL,
MENUNULL
* exclusion mutuelle * IntuiText *
* intitule em surbrillance * sequence de touches *
* sous-menu *
* NextSelect *
);
struct IntuiText itext2 =
3,1, COMPLIMENT,
0,0,
NULL,
"Cpen",
NULL
};
struct Menultem meruiteml =
&menuitem2,
0,0,80,8,
ITSKrEXT+CCKMSSO+ ITEKENXBLEEh-HIGHCCHP , 0,
(APTE)&itext2,
HIGHCOMP,
'o',
NULL,
MENUNULL
};
struct Menu menul =
NULL,
0,0,
111,0,
MENUrNABLED, "Open Window" fcmenuiteml
* structure Menu suivante * position *
* largeur et hauteur *
* flags du menu*
* ncm du menu *
* première option du menu
;
struct NewWindow nouvfenetrel =
50,25,300,100,
0,1,
MENUPICK+CLOSEWINDCW+MENUVERIFY,
WHJDOJSIZ ING+WINDCt,7DRAG+WINIXrWDEPTH+WTNDOtJULOSE,
NULL,
NULL, * image pour le CHECKMARK, NULL = défaut * "Une fenetre avec menu",
NULL,NULL,
50,50,640,200,
WBENCHSCREEN
};
struct NewWindow nouvfenetre2 =
350, 25, 150, 100,
0, 1,
NULL, NULL, NULL, NULL,
"Fenetre",
NULL, NULL,
5,5, 640,200,
WBENCHSCREEN
};

Ivf
£
?
SUITE DE LA PAGE 8
Programme principal (ne faic pas grand chose)
maint)
struct IntuiKessage «message; long GetMsgO;
ULONG classe_message; void init(), testmenu();
init();
fenetrel = OpenWindow(&nouvfenetrel); * on ouvre la fenetre * if (fenetrel == NULL)
printf("la fenetre est bloquée);
CloseLibrary(IntuitionBase); exit(FALSE) ;
SetMenuStrip(fenetrel,&menul); * On soumet les menus * while(1)
message = (struct IntuiKessage *)GetKsg(fenetrel->üserPort); if (message)
classe_message = message->Class;
ReplyMsg(message);
if (classe_message == CLOSEWINDCW)
* gadget fermeture de la fenetre actif *
if (fenetre2 != NULL) * si la fenetre existe * CloseWindow(fenetre2);
ClearMenuStrip(fenetrel);
CloseWindcw (fenetrel);
CloseLibrary(IntuitionBase); exit(TRUE);
)
if (classe__message == MENUPICX)
* bouton droit enfonce * testmenu(message);
Fccction gérant les différents menus.
....v
void testmenu (message) struct IntuiMessage «message;
_
US33PT num_suivant, numéro, num_ssfct, num_fct, num_menu;
if ( (num_suivant=message->Code) != MehTjNULL) » aucune sélection » if(ITEMNUM(num_suivant) == 0) * fonction Open *
rrum_ssfct = NOSUB; num_fct = 0; nua menu 0;
numéro = nua_ssfct*2048 + nnm_fct*32 + num_menu; fenetre2 = Cç>enWindcw(&nouvfenetre2) ;
OffHenu(fenetrel,numéro); * interdir Open *
)
if (ITaflîUK(nuni_suivant) == 1) * fonction close *
num_ssfct = N0SD3; num_fct = 0; num_menu = 0;
numéro = num_ssfct*2048 + num_fct*32 + nvm_menu;
if (fenetre2 != NULL) * si la fenetre existe *
CloseWindow(fenetre2); fenetre2 = NULL;
)
QnMenutfenetrel,numéro); * autoriser Open *
Fonction ouvrant la librairie intuition
void initO
char «OpenLibrary();
Intuition3ase = (struct IntuitionBase *)
OpenLibrary ( "intuition, library", D7ruiTICN_REV) ; if (IntuitionBase == NULL)
printf("mais ou est donc passe intuition "); exit(FALSS);
}
addq.1
.4, sp
* **
if (tdIO)
* * *

CioseDevice(tdlO);
* » *
DeleteStdIO(tdIO);
«**
.end3
move.1
tdIO(a5),d0
beq. S
. End4
movea.1
dO.al
tst.l
10 DEVICE(al)
beq. S
.end3.1
CALLEXEC
CloseDevice
. Er.d3.1
move.1
tdIO(a5),-(sp)
jsr
DeleteStdIO
addq.1
4, sp
...
exit() ;
. Er.d4
movea.1
DOSBase(pc),al
CALLEXEC
CloseLibrary
moveq
rts
S0,d0
* *****
...
A******************
; dans amiga.lib
Ici, on se fabrique deux routines différentes : la première, Printf, utilise RawDoFmtO lorsqu'il y a des nombres à sortir. La seconde, Puts, imprime directement la chaîne de caractères telle que passée en paramètre.
Putcn
move.b
dO,(a3)+
addq.1
* l,c7
rts
Printf
moveq
50,d7 ; RawDoFmtO n'utilise pas d7
lea
Putch(pc),a2 ; alors nous, on s'en se:
lea
bavard(aS),a3 ; compteur de caractères
clr .b
(a3) +
CALLEXEC
RawDoFmt
movea.I
a3,a0
move.b
d7,-(a0) ; et on tombe dans Puts
Puts
moveq
50, d3
move.b
(aO)+,d3
move.l
a0,c2
move.l
stdout(aô),dl
CALLDOS
Write
rts
getchar
move.l
stcin(a5),dl
lea
bavard(a5),a0
move. 1
a0,c2
moveq
51, d3
CALLDOS
Read
rts
VARS
ds.b
VARSI2E
DCSEase:
ds.l
1
dosr.ame
cc. b
"dos.library",0
even
tdname
cc. b
"trackdislc. Device", 0
even
Errl
DEFSTR
"Lmpossibie d'allouer le buffer">
Err2
DEFSTR
"Usage: Sectorise fichier secteur"»
Err5
DEFSTR
"Impossible d'ouvrir le trackdisk.device"»
ErrS
DEFSTR
"Disquette protégée en écriture"»
Err7.1
DEFSTR
• «"Dépassement du secteur 1759"»
Err7.2
DEFSTR
"Plus de place sur la disquette"»
Err8
cc. b
"Erreur trackdisk, code °od",10,0
Err3
dc. b
"Secteur de départ °-ai invalide", 10, 0
Err4
cc. b
"Lmpossible d'ouvrir le fichier %s",10,0
Ksgl
DEFSTR
«"Placer la disquette dans DF0:">
Msg2
DEFSTR
«"Puis taper [RETURN]">
:-!sg3.1
cc. b
"Premier secteur : °àd", 10, 0
Msg3.2
cc. b
"Dernier secteur : °«d",10,0
par DENIS JARML
m
C= AMIGA NEWS-TF.CH WJ NUMERO 34 JUIUAOIT
f
IRIREQUESTER V.2.4
Faut-il supprimer la disquette de l’ANT ? La question était posée dans Védito de l’ANT numéro 23. A l’augmentation du nombre d’articles s’oppose celle du prix de l’abonnement. Quelques lecteurs concernés nous ont d’ores et déjà communiqué leur sentiment à ce sujet.I
Cher journal, suite à l'interrogation par vous formulée dans votre numéro 23. Je prends la plume pour vous donner mon avis sur la modification de la formule d'abonnement, que vous soumettez à la sagacité de vos humbles lecteurs...
J'ai personnellement choisi la formule "I an sans disquette" pour disposer d'un magazine orienté programmation sur Amiga chaque mois et ne pas avoir à payer un surcoût inutile pour des disquettes qui, de toute façon, ne me serviraient pas. étant d'avantage intéressé par les techniques de programmation que les exemples d’application.
A priori, votre proposition équivaut, pour ceux qui ne désirent pas se procurer les disquettes, à transformer l'ANT en une revue de théorie technique et là, les débutants - dont je ne suis pas - devront sans doute déclarer forfait. Des articles sur la programmation sans programmes sont très complexes à exploiter pour quiconque n 'est pas technicien. L'alternative consiste à accepter de payer également pour les disquettes : vous modifiez alors la nature du magazine en multipliant (par combien au juste ?) Son prix.
Pour ma part, comme je ne tiens pas à acquérir des disquettes qui risquent d’être reformatées rapidement, pas plus que de recevoir un magazine au contenu nébuleux (je veux dire, sans les listings), il est vraisemblable que je ne renouvellerais pas mon abonnement si vous mettiez en place ce nouveau mode de fonctionnement.
C’était là mon opinion personnelle sur le sujet. Mais je laisserai à présent la parole aux autres abonnés qui ne manqueront pas d’exprimer la leur.
L. Depeux, Asnières Seine
Cher A NT. Je vous écris suite à la lecture de l'édito du numéro 23, que je viens à peine de recevoir. Si j’ai bien tout compris - car, comme d’autres avant moi, j’ai tout lu Freud... - il serait question de ne plus proposer que des abonnements avec disquette, gagnant ainsi la place utilisée dans le journal par les différents listings.
Cette idée me séduit : je suis pour l’instant abonné à la formule "5 numéros plus disquette" et je dois reconnaître que celle-ci fait un peu double emploi avec la revue. A part m'éviter un peu de fatigue et quelques inévitables fautes de frappe... Dans ma situation, le bénéfice serait évident : pour le même prix (enfin, j'espère...), je double mon volume d’articles intéressants.
Par contre, moi qui pensais changer d'abonnement pour passer à un an sans disquette, je vais sans doute réfreiner mes ardeurs... Le prix encore élevé ne m'autorise de tout façon pas l'année complète avec la disquette, donc... Je pense ne pas être le seul dans ce cas-Ià, n ’est-ce pas ?
François Jacquet, Nantes
Voilà donc deux premiers avis clairs et nets. Il n'est évidemment pas question de les discuter ici. Simplement, nous attendons un nombre incalculable de lettres avant de prendre notre décision. N'hésitez donc pas à nous écrire, la balle est dans votre camp.
Chers amis, si je vous écris aujourd'hui, c'est pour faire un peu le point sur l'ANT après quatre numéros reçus. Dans un mois, mon abonnement prendra fin et je me demande si je vais le renouveller. Non pas que TANT soit totalement inintéressant, bien au contraire, certains articles sont absolument passionnants (je pense notamment à l'Utilitaire de F. Mazué, qui nous en apprend toujours plus sur le système tout en ayant une utilité pratique). Je pense simplement que le rapport qualité-prix n 'est pas forcément à la hauteur de ce qu on pouvait espérer (le prix est très élevé !).
En effet, si quelques articles me semblent tout droit sortis des RKM (Subway I et II, CATS), je comprends parfaitement que tout le monde ne possède pas ces ouvrages, qui de plus sont en anglais. Le manque de documentation en français pour F Amiga fait sans doute de l'ANT un magazine indispensable, mais ce n'est pas une raison pour tomber dans le piège de la francisation des documentations étrangères déjà existantes ! Vous disposez d'assez de personnes compétentes pour vous permettre de faire preuve d'un peu plus d'originalité...
Mais le plus gros défaut que je puisse trouver à l’ANT est sans aucun doute la piètre qualité de la réalisation. Encore une fois, au prix du numéro, on est en droit d’attendre un magazine dont la maquette soit nickel et qui soit exempt de fautes d'orthographe... Or le numéro 23 est un véritable cauchemard : colonnes apparentes, nombreuses coquilles... Même votre concurrent Amiga-News, pourtant réputé - lui aussi - pour la toute relative qualité de sa mise en page était plus attrayant !
Jean-Pierre Dumest, Paris
La rubrique CATS seule est directement extraite et traduite des Rom Kernal Manuals. Subway, dont le but est d'initier le programmeur débutant aux joies de l’Amiga, s'en inspire sans doute fortement, et c'est inévitable, mais vous exagérez un peu en qualifiant cette rubrique de "francisation des documentations étrangères existantes". Prenons le cas de la série sur Intuition de notre Docteur national, et plus particulièrement le numéro de ce mois-ci. Concernant les menus : comment voudriez-vous qu'il puisse décrire chaque structure, chaque flag et chaque fonction sans ressembler à ce qui a déjà été imprimé ailleurs ? Bien sûr, vous pourrez toujours rétorquer, non sans un fond de pertinence, qu'il est toujours mieux et en tout cas plus instructif de mettre en pratique, plutôt que d'étaler inlassablement une mare de connaissances dans laquelle le lecteur ne pourra au bout du compte que se noyer. Soit, mais nous préférons quant à nous penser que c’est au lecteur de faire la part des choses et surtout le tri de ce qui l'intéresse. Ensuite, quand il aura compris les bases indispensables, il pourra, s’il en a envie, aller plus loin et mettre en pratique lui-même, en s’aidant au besoin des programmes publiés dans les autres rubriques ou dans les autres revues. Notre rôle n'est pas de vous prendre par la main mais de vous mettre sur le bon chemin.
Quant aux "imperfections" que vous mentionnez, elles existent, c'est vrai. Des coquilles arrivent à passer, malgré la vigilance du correcteur. La maquette a parfois des problèmes, c'est vrai aussi. Nous ne pouvons que nous en excuser et faire de notre mieux pour que celà ne se reproduise plus. C'est ce qu'on fait.
Cher A NT, n'ayant pas de Minitel le numéro de téléphone où appeler pour me faire aider, je vous pose ces quelques questions :
- le Pascal (n'22) ne comprend pas l’instruction ScreenPtr ("Unknown ID"). Ceci fait planter des exemples de la disquette (Bézier. 3D...). Or, j'ai bien tous les fichiers que vous mentionnez dans l'article. Si vous pouviez m'expliquer ?
- ma disquette qui contient le compilateur C de Matt Dillon (n°2I) est pleine alors que les Includes n ’v sont pas (je cherche toujours l’amiga.lib). Et si je fais une erreur, ou bien... ?
Pour terminer, une remarque sur la disquette de l'ANT : le Menu se bloque à la fin. Résultat : bootage obligé. Enfin, vous vous améliorez en numéro en numéro. J'attends ma demande de renouvellement avec impatience.
Emmanuel Melero, Saint Herblain
PCQ comprend parfaitement le type (et non l'instruction) ScreenPtr, pour peu que vous incluiez également lors de la compilation le fichier Screen.l qui se trouve dans votre répertoire PCQ:Include. Pour ne je ne sais quelle raison, l'auteur. Patrick Quaid. A oublié de le faire dans ses exemples. Ajoutez donc la ligne :
$ 1 "Include Screen. I" >
à vous sources pour que cela fonctionne.
Quant à DICE, tous les fichiers ne sont pas nécessaire sur la disquette : les sources des fonctions de la bibliothèque C peuvent être conservés ailleurs que la disquette du compilateur. Les seuls répertoires nécessaires sur la disquette DICE: sont c, bin. Dlib et include. Ils occupent environ 400 Ko, soit moins de la moitié de la disquette.
Par Vintermédiaire du journal Tilt. Infogrames a diffusé une démo du jeu Mystical. J'ai constaté que la Startup-Sequence commence par un petit programme appelé "reset" (cf. Listing ci-joint, obtenu bien sûr avec Devpac II...) qui effectue un NoFastMem résistant au Reset clavier I Pour remettre en service l'extension RAM, il faut éteindre et rallumer Tamiga !
Comme je trouvais cela pas très pratique, ni bénéfique pour les circuiis de T Amiga, j'ai potassé un peu la routine Reset du système (dans La Bible... Hé oui !). J’en ai conclu qu’en "faussant" ChkBase. On oblige à un resel plus "profond" qui reprend en compte l'extension RAM. J'ai donc modifié un petit poil la routine Clean_Reset de Frédéric Mazué, donnée dans TANT n°17 :
Clea~_Reset:
clr.l ChkBase(a6) ; a6 = ExecBase après SuperVisorO lea.l S2,aO RESET j=p (aO)
El ça marche ! Cela intéressera sûrement les lecteurs ayant eu le problème.
Maintenant, une question : parlerez-vous dans FAUT du débogueur ROM-Wack inclus dans la ROM KickStart. De ses commandes et de la manière de s'en servir à partir d'un terminal ?
En tout cas. Bravo et merci pour TANT.
G. Boulay, Paucourt
; Programme "RESET" de la démo de Mystical ; Débraye l'extension RAM: d'une manière qui ; résiste au reset CTRL+A+A MOVEA.L 4 , A6
MOVE.L$ 4E(A6),DO ; $ 4E = MaxExtMem BEQ fin
MOVE.B 3, $ BFE201 MOVE.B 2, $ BFE001 LEA $ DFF000,A4 MOVE.W $ 7FFF, DO MOVE.WDO, $ 9A(A4 )
MOVE.W DO, $ 9C (A4 )
MOVE.W DO, $ 96 (A4)
MOVE.W $ 200, $ 100 (A4)
MOVE.W 0, $ 110 (A4)
MOVE.W $ 444, $ 180 (A4)
LEA $ 400,A6 SOBA.W $ FD8A, A6 LEA $ C00000,A0 LEA $ DC0000,Al
MOVEA.L 0,A4 ; Pas d'extention !
MOVE . L A4 , D0 MOVEA.L $ 40000,A7 MOVE.L $ FFFFFFFF,D6
JMP $ FC0208 ; Reset en ROM (beurk !!)
Fin: RTS
A la lumière de ce listing, on peut dire que les programmeurs de chez Infogrames ne se cassent pas vraiment la tête ! Non seulement cette pratique est indigne de 1 Amiga (et en plus y'a un saut en ROM ! La honte sur eux !), mais ils ne se soucient même pas de savoir si l'extension est de type FAST ou CHIP, auquel cas ils pourraient l'exploiter ! Merci donc pour ton reset à toi. Beaucoup plus propre.
Quant à ROM-Wack. Il fonctionne avec un terminal série configuré à 9600 bauds. 8 bits de données, pas de parité. 1 bit de stop. Sans trop connaître la question, je pense que le Minitel (au moins le M2) pourrait parfaitement convenir. S'il s'avère que c'est le cas, nous en parlerons certainement dans une prochaine rubrique ExecBase.
Bonjour à tous ! Le but de cette lettre n'est pas seulement de poser des questions, auxquelles je suis sûr que vous répondriez de toute façon, mais plutôt de vous soumettre quelques suggestions d’articles pour les numéros à venir.
- comment se fabriquer une librarie personnelle, contenant toutes mes routines les plus fréquemment utilisées, que mes programmes n'auraient plus qu’à ouvrir quand ils en auront besoin ? Cela réduirait leur taille de façon conséquente et me permettrait d'améliorer certaines routines sans avoir à ré-assembler chaque programme qui les utilise. La documentation que l'on peut trouver dans la Bible de l'Amiga est loin d'être suffisante... De plus, vues les similitudes entre les deux, cet article pourrait déboucher sur un autre traitant de la création d’un device particulier.
- en parlant des devices, je possède une imprimante DMP 2160 d'Amstrad, dont j"aimerais exploiter toutes les possibilités avec mon Amiga. Ce que le driver d'imprimante EpsonFx ne me permet pas. Un article traitant donc de la création d'un driver particulier me semblerait fort utile. Dans le même genre d'idées, n’y a-t-il pas quelque chose à faire avec les keymaps ?
- pourquoi ne parlez-vous plus de l’AmigaBasic ni du GfABasic dans FAUT? Ces deux langages sont pourtant souvent utilisés, surtout le GfA. D'autant plus que son compilateur est sorti et que vous en avez vous même fait l'éloge!
Bien sûr, ces quelques suggestions sont en rapport direct avec les problèmes que je rencontre à la maison. Toutefois, je suis certain que je ne suis pas le seul et que d'autres lecteurs seraient ravis de trouver ce genre d’articles dans l’ANT.
Jérôme Apietto, Savigny Orge
Une série d'articles sur les bibliothèques ("library" est le terme anglais) est justement en préparation. Le premier épisode devrait être - j'espère - publié dans le numéro 26 ou 27. Il n'était pas prévu d'y inclure les devices, mais si celà intéresse suffisamment de lecteurs, nous y viendrons.
Un driver d'imprimante ? L'idée n'est pas mauvaise, mais le problème est d'en choisir un qui puisse être utile à la majorité des lecteurs. Beaucoup semblent avoir conservé leur DMP en passant à l'Amiga. Alors pourquoi pas?
L'AmigaBasic n'est plus réellement utilisé, sauf peut-être par quelques rares masos. Et encore... Quant au GfA, s'il s'avère que la sortie du compilateur a relancé l'intérêt de ce langage, nous y reviendrons sûrement. Encore une fois, il n'est pas possible de contenter toute le monde, et nous devons nous conformer à l'avis de la majorité. Or il ne me semble pas que la majorité des lecteurs de l’ANT soit attirée par ce langage. Aujourd'hui, C et assembleur sont les maîtres absolus, et le Basic n’a pas beaucoup d'avenir sur notre machine.
Voici la fin des recommandations du Commodore-Amiga Technical Suppoh, sur la manière de réaliser des programmes ayant le ' 'look-and-feel ' ' Amiga.
Tilisez les deux touche Amiga comme des touches Shift supplé- mentaiies. La touche .Amiga de gauche est utilisé pour les raccourcis clav ier et par Intuition, celle de droite, pour sélectionner des options de menus sans toucher à la souris. Le tableau-ci dessous liste quelques recommendations pour l'utilisation de la touche Amiga de gauciie :
u
autres (géré automatiquement par Intuition) Place l’écran du WorkBench derrière tous les autres (géré par Intuition)
Répond "oui" à un AutoRequester Répond "non" à un AutoRequester
B
V
I
o
sélectionne une petite partie du document, à droite du cureur (ex : le mot suivant) sélectionne une partie du document, à droite du curseur (ex : la prochaine ligne) sélectionne une grande partie du document, à droite du curseur (ex : le prochain paragraphe)
MMHM
sélectionne une petite parue du document, à gauche du cureur (ex : le mot procèdent) sélectionne une partie du document, à gauche du curseur (ex : la ligne précédente)
J
K
sélectionne une grande partie du document, à gauche du cuiseur (ex: le paragraphe procèdent)
Le tableau suivant liste les raccourcis standard à utiliser avec la touche Amiga droite. Les programmes devraient proposer autant de raccourcis que possible : l'utilisateur confirmé apprend vite à se servir du clavier, tandis que le novice continue à utiliser la souris et les menas.
Couper (eut)
X
C
V
I
B
ü
P
Z
O
S
Q
Copier (copv)
• Coller (pasté) Italiques (itaiies) Gras(boW) Souligné (underline) Normal (plain) lindo
Ouvrir (open) Sauver (save) Quitter (quit)
LA TOUCHE HELP
Prenez en compte la touche Help. Si votre application dispose d'une aide en ligne intégrée, la touche Help est un bon moyen de l'obtenir. Imaginez la tête de l'utilisateur pondu, qui appuie sur Help alors que rien ne se passe...
LE CURSEUR
Les louches fléchées sont un moyen pratique de contrôler les mouvements du curseur. Voici nos recommandations quant à leur utilisation :
Flèche et.. Déplacement
1: unité la plus petite (un caractère ou une ligne)
(rien)
ALT
SHIFT
S5SSS5
CTRL
l'unité immédiatement supérieure (un mot ou une page)
la plus grande unité (fin de ligne, début de document)
Spécial ai sans effet
LA SOURIS
Intuition utilise le bouton gauche de la souris pour la sélection et le bouton droit, pair le transfert d'informations. Noo> votes encourageons à suivre ce node le. Pour aider l'utilisateur à comprendre le fonctionnement de chaque application, et à s'en souvenir. Quand l'utilisateur ap>puie sur le bouton gauche. Intuition examine l'état du système et la position du pointeur. Ces information. sont utilisées pour décider si l'utilisateur essaye de sélectionner un objet, une opération ou une option. Par exemple, l'utilisateur positionne le pointeur sur un gadget et appuie sur le bouton gauche pour le sélectionner. S'il déplace la souris tout en maintenant le bouton appuyé, cela signifie sans doute qu’il désire déplacer ce gadget.
Intuition utilise le bouton droit pour les opérations de menu. Une pression sur le bouton droit affiche nonnalemeni la barre de menu. Si l'utilisateur déplace la souris tait en mai menant le bouton droit appuyé, il est sans doute en train de se promener dans le menu, à la recherche d'une option particulière. Un double clic du bouton droit peut faire apparaître un Requester spécial, que l'on peut considérer comme une extension aux menas. Ce Requester étant destiié à recev oir des informations, il est conect de l'assigner au baiton droit.
Si vous décidez de gérer vous-même les événements en provenance de la souris, conformez-vais le plus possible à ce nxxlèle.
ECRAN ET FENETRE
Pemiettez toujairs à l'utilisateur d'av oir accès à la barre de l'écran (ce peut être aassi simple que d'aivrir votre fenêtre un pixel en dessais du haut de l'écran). Evitez d'aivrir des fenêtres plein-écran qu'on ne peut déplacer ni changer de taille, surtout si vais utilisez l'écran du Workbench.
De même, si voue programme ne dépend pas particulièrement de la taille de sa fenêtre, fixez ses limites MaxWidth et MaxHeighl à -1 : l'écran utilisé peut être pkis grand que le 640 x 256 standard.
Quand vous aivrez un CastomScteen. Redirigez-y les Requester d'AtrrigaDOS (champ pr_ VindowPtr de la structure Piocess). Sinon Intuition amènera l'écran du Workbench devant tous les autres. Vais devez restaurer le pointeur avant de fermer la fenêtre.
DI ERS
Un programme devrait taijairs appeler OpenWorkbenchO avant de quitter, même s'il n'a pas appelé Close Workbendk ) auparavant : si un autre programme a tèrmé le Workbench et que la fin du voue a libéré suffisament de mémoire pair lui permettre de se rouvrir, il est préférable qu'il le fasse. Le Workbench devrait être ouvert le plas saivent possible, cela aide l'utilisateur à garder un environnement consistant Intuition vérifie taijairs. Lorsqu'un programme ferme un écran, que ce n'était pas le dernier, aiquel cas celui du WaLbench doit être ré-ouvert.
Autorisez tant que fait se peut l'utilisateur à configurer ies paramètres de votre programme. Par exemple, si vais aivrez un CustomScreen. Laissez-lui la possibilité d'en changer les caileurs. Si votre logiciel produit du son. Permettez-lui d'en modifier le ton et le volume. Ne rendez cependant pas la indispensable, et laissez toujours une possibilité de rev enir aux réglages par défaut
COULEURS
Intuition utilise les couleurs suivantes pair le pointeur de la souris (entre parenthèses, le numéro du registre de couleur hardware correspondant )
intensité moyenne basse intensité hauteintensûé..
Entairez votre pointeur personnel d'un filet de couleur 1 ou 3.
Le pointeur de souris étant taijours le sprite 0. Vous pouv ez en changer les couleurs en appelant SelRGB-ti ) avec le VievvPort de n'importe quel écran, même s'il n'a que deux couleurs. Par exemple :
struct Screen *mvScreen:
SetRGV-k&myScredi->VievvPort 17. R17. V17. B17) SetRGXW SmiyScreen->VievvPort 18. R18. V18. B18 ) SetRGV-ti &mvScreen->VievvPorL 19. R19. V19. B19 )
ICONES
Vos icônes devraient être dessinées avec une source lumineuse venant du coin haut gauche de l'écran, et être visibles avec 1 ou 2 plans de bits. Dessinez de belles icônes, qui reflètent l'utilité de votre programme, mais surtout qui ne soient pas trop grandes : cela prend de la place à l'écran, en mémoire et sur disquette. Ayez une approche minimaliste quand vous dessinez VOS icônes. (Cl 1987. 1991 Commodore Amiga Technical Support
res plein-écran qu'on ne peut déplacer ni changer de taille, surtout si vais utilisez l'écran du Workbench. De même, si voue programme ne dépend pas particulièrement de la taille de sa fenêtre, fixez ses limites MaxWidth et MaxHeighl à -1 : l'écran utilisé peut être pkis grand que le 640 x 256 standard.
Quand vous aivrez un CastomScteen. Redirigez-y les Requester d'AtrrigaDOS (champ pr_ VindowPtr de la structure Piocess). Sinon Intuition amènera l'écran du Workbench devant tous les autres. Vais devez restaurer le pointeur avant de fermer la fenêtre.
DI ERS
Un programme devrait taijairs appeler OpenWorkbenchO avant de quitter, même s'il n'a pas appelé Close Workbendk ) auparavant : si un autre programme a tèrmé le Workbench et que la fin du voue a libéré suffisament de mémoire pair lui permettre de se rouvrir, il est préférable qu'il le fasse. Le Workbench devrait être ouvert le plas saivent possible, cela aide l'utilisateur à garder un environnement consistant Intuition vérifie taijairs. Lorsqu'un programme ferme un écran, que ce n'était pas le dernier, aiquel cas celui du WaLbench doit être ré-ouvert.
Autorisez tant que fait se peut l'utilisateur à configurer ies paramètres de votre programme. Par exemple, si vais aivrez un CustomScreen. Laissez-lui la possibilité d'en changer les caileurs. Si votre logiciel produit du son. Permettez-lui d'en modifier le ton et le volume. Ne rendez cependant pas la indispensable, et laissez toujours une possibilité de rev enir aux réglages par défaut
COULEURS
Intuition utilise les couleurs suivantes pair le pointeur de la souris (entre parenthèses, le numéro du registre de couleur hardware correspondant )
intensité moyenne basse intensité hauteintensûé..
Entairez votre pointeur personnel d'un filet de couleur 1 ou 3.
Le pointeur de souris étant taijours le sprite 0. Vous pouv ez en changer les couleurs en appelant SelRGB-ti ) avec le VievvPort de n'importe quel écran, même s'il n'a que deux couleurs. Par exemple :
struct Screen *mvScreen:
SetRGV-k&myScredi->VievvPort 17. R17. V17. B17) SetRGXW SmiyScreen->VievvPort 18. R18. V18. B18 ) SetRGV-ti &mvScreen->VievvPorL 19. R19. V19. B19 )
ICONES
Vos icônes devraient être dessinées avec une source lumineuse venant du coin haut gauche de l'écran, et être visibles avec 1 ou 2 plans de bits. Dessinez de belles icônes, qui reflètent l'utilité de votre programme, mais surtout qui ne soient pas trop grandes : cela prend de la place à l'écran, en mémoire et sur disquette. Ayez une approche minimaliste quand vous dessinez VOS icônes. (Cl 1987. 1991 Commodore Amiga Technical Support

Click image to download PDF

AMIGA NEWS TECH numero 24 (07-08-1991)

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


Thanks for you help to extend Amigaland.com !
frdanlenfideelhuitjanoplptroruessvtr

Connexion

Pub+

34.7% 
16.2% 
6.8% 
5.4% 
4.3% 
3.5% 
3% 
2.4% 
1.6% 
1.1% 

Today: 51
Yesterday: 86
This Week: 51
Last Week: 630
This Month: 2027
Last Month: 3072
Total: 66167

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