|
||||||||||||||||||||||||||||||||||||||||||||||
|
Pourquoi le Copper ? Quelqu'un m'a un jour dit que les ingénieurs de Commodore avaient créé le Copper dans le seul but de faciliter le chevauchement des différents écrans Intuition (partie du système d'exploitation Amiga qui gère la partie graphique et notamment le système fenêtré). Ainsi, par exemple, un écran pouvait contenir un traitement de texte monochrome, haute résolution, tandis qu'un autre contiendrait le logiciel Deluxe Paint affichant une image en mode HAM, c'est-à-dire en 4096 couleurs. Lorsque vous faites glisser un écran verticalement, laissant apparaître deux écrans se chevauchant avec des modes graphiques différents, l'effet est garanti, du moins à l'époque il l'était. Je ne peux pas affirmer que cette explication de l'origine du Copper soit vraie, car je n'ai pas trouvé de référence crédible, mais à y réfléchir, cette explication me semble logique et cohérente car je vois mal comment Intuition se débrouillerait sans le Copper pour changer de mode graphique à la volée. ![]() Figure 1 : bureau d'un Amiga 500 avec deux écrans de résolution et nombre de couleurs différents Dans un premier temps, nous allons effectuer un tour d'horizon assez sommaire mais néanmoins nécessaire des caractéristiques du Copper. Cela nous servira de préambule à la deuxième partie qui, elle, sera plus terre à terre, à savoir la conception d'un programme assembleur utilisant la capacité du Copper à produire de jolies couleurs. Le punk et le métronome Durant mon adolescence, j'ai fait partie d'un groupe de musique, groupe duquel je me suis fait virer assez rapidement. Hors sujet, voire inintéressant à souhait, je vous l'accorde. Mais ce qui est intéressant, c'est la raison principale pour laquelle j'ai dû le quitter : je n'arrivais pas à me caler sur le tempo des autres membres, je tapais systématiquement à côté des battements du métronome. Il faut croire que cela avait une importance capitale, même si ce n'était qu'un groupe de punk. Pour le Copper, c'est pareil : pour pouvoir être efficace et devenir une réelle valeur ajoutée aux fonctionnalités graphiques de l'Amiga, il se doit d'être parfaitement synchronisé et garder le tempo dicté par l'affichage de l'écran. D'ailleurs, à ce sujet, si vous n'avez aucune idée de la manière dont l'affichage se déroule sur Amiga, je vous conseille vivement de lire cet article. Le Copper est un coprocesseur qui a deux caractéristiques principales. La première, comme déjà évoqué, est qu'il doit être synchronisé avec l'affichage, et la deuxième tout aussi importante, est qu'il doit pouvoir altérer en temps réel les registres Amiga qui pilotent l'affichage. Il peut faire d'autres choses, mais dans le cadre de cet article, elles sont d'un intérêt limité, donc non évoquées. Si on se réfère à la figure 1 ci-dessus, on observe qu'à mi-chemin, à peu près, l'écran change de mode graphique. On passe d'un écran 640x256 en 4 couleurs vers un écran 320x256 en HAM. Ce petit miracle est le fruit d'instructions Copper. Ce dernier a reçu l'ordre, strict mais nécessaire, que lorsqu'il se trouvera à cette limite verticale entre les écrans, il devra changer les registres graphiques de l'Amiga pour modifier le mode d'affichage et la palette, et ceci en temps réel, à chaque trame ; cela permettra à chaque écran d'avoir un affichage en adéquation avec son contenu. La ligne, les cycles et le Copper Comme on peut le deviner aisément, une image envoyée par l'Amiga se construit progressivement grâce à un point lumineux qui balaye le moniteur ligne par ligne et durant chaque ligne, de gauche à droite. Le Copper est parfaitement synchronisé sur ce cheminement. C'est-à-dire qu'il suit le point lumineux qui chemine sur le moniteur. Il le suit comme son ombre, sans jamais le quitter d'une semelle. Le temps nécessaire au trajet d'une ligne est de 225 cycles machine. Ces cycles sont numérotés en hexadécimal de $00 à $E0, l'équivalent en décimal est 0 à 224. Ces différents cycles sont distribués aux différents organes de la machine via les canaux DMA et aussi au processeur principal 68000 par un coprocesseur complexe nommé Agnus (il contient, entre autres, le Copper). Cette distribution est séquentielle et exclusive : un cycle sera alloué à un et un seul organe donné à la fois. Mais que peut bien faire l'Amiga durant le temps d'affichage de cette ligne ? Comme le montre le diagramme de la figure 2 ci-dessous, beaucoup de choses en fait. Mais ce qui nous intéresse et sur lesquels nous allons porter une attention particulière, ce sont les cycles qui se situent dans l'intervalle [$30,$E0]. Cet intervalle est la limite affichable constatée des changements de couleurs horizontaux visibles mais, en pratique, cela dépend du type de moniteur utilisé. ![]() Figure 2 : allocations des cycles durant la durée d'affichage d'une ligne (Source : Hardware Reference Manual) Cliquez sur l'image pour l'agrandir Entrée en scène du Copper Le Copper est un processeur très simple en fait. Il ne connaît que trois instructions :
L'instruction MOVE Permet d'écrire des valeurs numériques dans les registres spécialisés de l'Amiga. Une majorité, mais pas tous, de registres peut être accédée via cette instruction. L'adresse de base qui sert de calcul aux registres accessibles par le Copper est $DFF000. Une instruction MOVE complète tient en deux mots (2x2 octets ou encore 2x16 bits). Le premier mot est l'adresse relative du registre à altérer. Le second est la valeur qui sera injectée dans ce même registre. Par exemple, si l'on désirait modifier la couleur de fond de l'écran en 68000 on procéderait comme suit :
L'instruction Copper équivalente est :
Ces deux instructions modifient l'adresse $DFF180 en y injectant la valeur 16 bits VALEUR. Il ne vous aura pas échappé que le premier mot étant une adresse relative des registres spécialisés, il est par définition toujours pair. Et c'est précisément cette caractéristique qui permet au Copper de reconnaître une instruction MOVE. Le premier mot d'une instruction, s'il est pair, sera reconnu par le Copper comme étant un MOVE. L'instruction WAIT Elle permet d'attendre qu'une position à l'écran du faisceau à électrons du moniteur soit atteinte. Tant que ce ne sera pas le cas, le Copper restera sur cette instruction WAIT. Dès que la position spécifiée est atteinte ou dépassée, l'instruction suivante sera exécutée. Comme pour MOVE, l'instruction WAIT est composée de deux mots. Le premier contient les coordonnées à atteindre. Le deuxième, quant à lui, est un masque qui permet d'affiner ou non la précision de l'attente. Plus il y a aura de bits activés, plus fine sera la coordonnée cible. Malheureusement, même en activant un maximum de bits dans le masque, on ne pourra jamais atteindre le degré de précision ultime d'une position (x,y) qui serait au pixel près. Au mieux, on aura une précision horizontale de quatre pixels en basse résolution. Toujours horizontalement, WAIT attendra une abscisse qui correspondra à un numéro de cycle de la ligne. WAIT compte donc en cycle. Et si l'on se réfère à la figure 2, l'abscisse d'attente sera un nombre compris dans l'intervalle [$1,$DF]. Pourquoi pas [$0,$E0] ? Parce que WAIT ne peut attendre que des abscisses impaires. L'explication est simple. Un exemple d'instruction WAIT est comme suit :
Petite consolation tout de même, verticalement, on pourra attendre n'importe quelle ligne qui compose l'écran, sans restriction. L'instruction SKIP Cette instruction un peu particulière permet de simuler des branchements conditionnels, donc par extension, le traitement de boucles. Pour être honnête, je ne l'ai jamais utilisée. Mais si d'aventure je l'ai déjà fait, ce souvenir est perdu dans les méandres de ma mémoire. Non pas qu'elle est inutile, bien au contraire, mais j'ai pris l'habitude (mauvaise probablement) de n'utiliser que des MOVE et WAIT plus une instruction de saut COPJMP pour générer des pseudos boucles. Je dois me rendre à l'évidence, cette méthode est moins élégante que l'utilisation des SKIP. Elle peut être utile pour générer à moindre coût des motifs répétitifs de la liste Copper. ![]() ![]() Figure 3 - structures des instructions (source : La Bible De L'Amiga) Cliquez sur l'image pour l'agrandir Pour pouvoir utiliser le Copper, il faut l'activer. Ou plutôt, activer son DMA. En faisant ça, le Copper obtient l'accès à la mémoire Chip (de toute façon, il ne peut pas accéder à un autre type de mémoire). Les instructions sont contenues dans un programme qu'on appellera "Liste Copper". On indique au Copper où se trouve cette liste dans un registre spécial ($DFF080 ou $DFF084). Une fois tout ceci effectué, le Copper démarrera automatiquement à la ligne 0 de la prochaine trame. Voilà, très sommairement ce qui passe pour le Copper durant une trame. En tout début de ligne (ligne 0), durant le tout premier cycle, le Copper démarre en exécutant la première instruction. Puis, cela coule de source, il exécute les instructions suivantes de sa liste. Une fois dépassé la dernière ligne d'affichage, le compteur de programme interne du Copper se réinitialise pour se placer automatiquement au début de la liste Copper, et ainsi de suite. Si votre écran est basique, sans fioriture dans sa structure, il est tout à fait possible de se passer du Copper pour recharger les registres d'affichage pour le faire via le 68000. Mais, à moins que vous ayez une raison valable et spécifique, je déconseillerais de le faire. Le Copper est plus rapide, plus sûr, plus stable pour effectuer cette tâche. De plus, le 68000 peut se faire interrompre de manière inopinée et ainsi rendre la synchronisation horizontale ou verticale avec l'affichage plus ardue. Les stabilisation et synchronisation avec l'affichage peuvent se révéler complexes à mettre en place, pour vous en rendre compte, posez la question aux possesseurs de Commodore 64 ou d'Atari ST qui eux n'ont pas de Copper. L'article touche à sa fin, du moins pour la première partie. Comme à mon habitude je vous fournis quelques références utiles, voire indispensables. Je vous revois avec grand plaisir pour la deuxième partie. Références de lecture
|