Section courante

A propos

Section administrative du site

Introduction

La console de jeux Atari Jaguar est un système de jeu vidéo de cinquième génération présenté comme la première console 64 bits au monde. Il a été mis en vente à l'automne 1993 avec un emballage de vente au détail de 249 $ USD comprenant la Jaguar, un contrôleur, des connexions de télévision et une cartouche de jeu Cybermorph. Le Jaguar a une petite bibliothèque de jeux avec des titres notables incluant Tempest 2000, Doom, Wolfenstein 3D, Myst et Alien vs. Predator.

Fiche technique

Voici les caractéristiques du «Jaguar» de «Atari» :

Spécification Description
Fabricant Atari
Modèle Jaguar
Date de fabrication 1993
Catégorie Console de jeux
Microprocesseur Motorola 68000, 2 processeurs RISC personnalisés, environ 13,295 MHz
Mémoire vive (RAM) 2 Mo
Tom GPU RISC 32 bits, environ 26,59 MHz, RAM locale 4 Kio
Tom Object Processor Moteur d'objets et scanlines, chemin 64 bits
Tom Blitter Moteur 64 bits, pixels, Z-buffer et Gouraud
Jerry DSP RISC 32 bits, environ 26,59 MHz, RAM locale 8 Kio
RAM principale 2 Mio DRAM, bus 64 bits
ROM cartouche Jusqu'à 6 Mio dans la fenêtre standard
Vidéo Minuterie programmable, palettes/CRY/RGB
Audio DAC stéréo via DSP, qualité/cadence programmable
Contrôleurs Deux ports, disque D-pad, boutons et clavier 12 touches
Sauvegarde EEPROM série optionnelle dans cartouche
CD Double vitesse avec DSP/contrôleur dédiés dans l'extension

Historique et positionnement

La Jaguar est une console de jeux vidéo commercialisée par Atari à partir de 1993 aux États-Unis, avant d'être distribuée dans d'autres régions du monde. Elle apparaît à une période de transition importante pour l'industrie du jeu vidéo, alors dominée par les consoles 16 bits mais déjà tournée vers une nouvelle génération de machines capables d'afficher des graphismes plus complexes, de manipuler davantage de couleurs et de proposer des jeux utilisant massivement la 3D. Atari cherche avec la Jaguar à reprendre une place importante sur le marché des consoles de salon.

L'architecture de la Jaguar est construite autour des deux circuits personnalisés TOM et JERRY, issus de travaux réalisés avec Flare Technology. Ces puces regroupent une grande partie des fonctions spécialisées de la console. TOM prend notamment en charge le GPU, le Blitter, l'Object Processor et les fonctions vidéo, tandis que JERRY regroupe entre autres le DSP, les fonctions audio, des minuteries et différentes interfaces. Le Motorola 68000 complète l'ensemble en assurant principalement le démarrage, la logique générale et la coordination des différents composants.

Atari positionne commercialement la Jaguar comme la première console 64 bits. Cette désignation repose notamment sur certaines parties de son architecture capables de manipuler ou de transférer des données sur 64 bits, en particulier le chemin mémoire exploité par certains circuits graphiques comme le Blitter et l'Object Processor. L'ensemble de la machine n'est cependant pas constitué exclusivement de processeurs 64 bits : le Motorola 68000 possède notamment un bus externe de 16 bits, tandis que le GPU et le DSP sont des processeurs RISC 32 bits.

Cette présentation « 64 bits » devient néanmoins l'élément central de la stratégie publicitaire d'Atari. La société utilise notamment le slogan « Do the Math », destiné à souligner l'avantage numérique revendiqué de la Jaguar face aux consoles 16 et 32 bits concurrentes. Le nombre 64 devient ainsi une partie importante de l'identité commerciale de la machine, même si l'architecture réelle de la Jaguar est beaucoup plus complexe qu'une simple classification fondée sur un nombre de bits.

Sur le plan technique, la Jaguar possède effectivement plusieurs capacités particulièrement intéressantes pour son époque. Son architecture est très efficace pour certaines opérations sur les bitmaps, notamment grâce au Blitter et à l'Object Processor. Ce dernier peut composer l'affichage ligne par ligne à partir d'une liste d'objets et prendre directement en charge des objets redimensionnés. Cette approche permet de construire des scènes 2D élaborées sans nécessairement demander au processeur principal de dessiner chaque élément dans un framebuffer complet.

Les processeurs RISC intégrés à TOM et JERRY constituent une autre caractéristique importante de la console. Le GPU peut effectuer des calculs graphiques, construire des spans, préparer des commandes pour le Blitter, réaliser certaines transformations ou participer à la décompression de données. Le DSP peut, de son côté, effectuer des calculs numériques rapides et prendre en charge une grande partie du traitement audio. La Jaguar offre ainsi au développeur plusieurs unités spécialisées capables de fonctionner en parallèle.

Son système sonore est lui aussi fortement programmable. Plutôt que de dépendre exclusivement d'une puce sonore proposant un ensemble fixe de canaux ou de formes d'onde, la Jaguar peut utiliser le DSP pour générer, transformer et mélanger numériquement la musique et les effets sonores. Cette souplesse permet d'envisager des moteurs audio très différents selon les besoins du jeu, à condition de fournir le logiciel nécessaire pour exploiter correctement le DSP.

Cette puissance théorique s'accompagne toutefois d'une difficulté importante : la Jaguar possède une architecture parallèle relativement complexe. Pour obtenir de bonnes performances, le programme doit répartir intelligemment le travail entre le 68000, le GPU, le DSP, le Blitter et l'Object Processor. Ces unités partagent en outre différentes ressources, notamment la DRAM principale et le bus mémoire. Une mauvaise organisation peut donc provoquer de la contention et empêcher le programme d'exploiter la puissance disponible.

Le développement est encore compliqué par plusieurs errata et particularités du silicium. Le GPU et le DSP présentent notamment des contraintes concernant le pipeline, les dépendances entre instructions, les branchements, les interruptions et certaines opérations mémoire. Les développeurs doivent connaître ces comportements et appliquer les solutions de contournement appropriées. Une routine théoriquement correcte d'après une lecture simplifiée de l'architecture peut ainsi nécessiter des précautions supplémentaires pour fonctionner de manière fiable sur le véritable matériel.

Plusieurs jeux commerciaux montrent cependant que la Jaguar pouvait produire des résultats très différents selon la manière dont son architecture était exploitée. Tempest 2000 utilise notamment la machine pour créer un jeu extrêmement rapide combinant graphismes, effets visuels et animation dans une présentation très différente des jeux traditionnels de l'époque. Il constitue l'un des titres les plus étroitement associés à l'identité de la Jaguar.

Alien vs Predator illustre une autre utilisation du matériel avec un jeu centré sur une représentation en vue subjective et une atmosphère reposant fortement sur son environnement graphique. Doom, adaptation du célèbre jeu d'id Software, montre encore une autre approche du rendu en temps réel et constitue un exemple important de l'utilisation de la Jaguar pour un moteur de type first-person shooter.

Rayman démontre pour sa part les qualités de la machine dans un contexte très différent. Son univers repose davantage sur des graphismes 2D détaillés, de grandes images colorées et des animations élaborées. La présence sur une même console de titres aussi différents que Tempest 2000, Alien vs Predator, Doom et Rayman montre que l'architecture de la Jaguar ne se limitait ni à la 2D ni à la 3D, mais pouvait être exploitée selon des stratégies graphiques très différentes.

Malgré ses capacités techniques et son positionnement ambitieux, la Jaguar ne réussit pas à s'imposer durablement sur le marché. Sa programmation difficile, sa bibliothèque de jeux relativement limitée et l'évolution rapide de la concurrence réduisent progressivement sa place commerciale. Au début de 1996, face aux faibles ventes et à une concurrence devenue beaucoup plus forte, Atari réduit fortement ses activités liées à la Jaguar et cesse sa production. La société conclut ensuite son rapprochement avec le fabricant de disques durs JTS, la fusion étant finalisée le 31 juillet 1996. Cette opération marque la disparition d'Atari Corporation comme constructeur actif de consoles, même si des stocks de Jaguar et quelques jeux continuent d'être commercialisés par la suite.

La Jaguar occupe ainsi une position particulière dans l'histoire des consoles. Présentée comme une machine 64 bits sous le slogan «Do the Math», elle combine en réalité plusieurs architectures de calcul et des moteurs spécialisés travaillant en parallèle. Ses capacités pour les bitmaps, les objets redimensionnés, les calculs RISC et l'audio programmable étaient importantes, mais leur exploitation demandait une connaissance approfondie du matériel et de ses errata. Les différences considérables entre des jeux comme Tempest 2000, Alien vs Predator, Doom et Rayman illustrent précisément cette architecture : la Jaguar offrait plusieurs chemins pour produire un jeu performant, mais la qualité du résultat dépendait fortement de la manière dont le logiciel répartissait le travail entre ses nombreux composants.

La machine est puissante pour les bitmaps, objets redimensionnes, calculs RISC et audio programme, mais son architecture parallèle et ses errata compliquent le développement. Tempest 2000, Alien vs Predator, Doom et Rayman illustrent des utilisations très différentes du matériel.

Modèles et dérives

CoJag peut utiliser 68020 ou MIPS, davantage de RAM et bus ROM différent. Il ne doit pas être traité comme une simple révision de la console de salon.

Architecture fonctionnelle

L'architecture de la console Atari Jaguar repose sur plusieurs processeurs et circuits spécialisés qui travaillent en parallèle. Le Motorola 68000 assure principalement les fonctions générales et la coordination du système, tandis que les puces personnalisées TOM et JERRY regroupent les unités spécialisées chargées du graphisme, de la vidéo, du son et de différentes fonctions d'entrée-sortie. La Jaguar doit donc être considérée comme une architecture multiprocesseur dans laquelle les performances dépendent fortement de la coopération entre ces différents composants.

La puce TOM regroupe l'essentiel du sous-système graphique de la console. Elle contient notamment le circuit vidéo, l'Object Processor (OP), le GPU (Graphics Processing Unit) et le Blitter. Chacun possède une fonction particulière. Le GPU effectue des calculs programmables, le Blitter accélère les opérations sur les pixels et les blocs de mémoire, l'Object Processor compose les lignes destinées à l'affichage à partir d'une liste d'objets, tandis que le bloc vidéo transforme finalement les données produites en un signal adapté à la sortie vidéo.

La puce JERRY complète cette architecture en regroupant principalement les fonctions liées au son et à certaines entrées-sorties. Elle contient notamment le DSP (Digital Signal Processor), les circuits audio, différentes minuteries, une interface UART ainsi que d'autres interfaces matérielles. Le DSP constitue un processeur RISC programmable pouvant être utilisé pour effectuer rapidement les calculs nécessaires au traitement numérique du son, mais également pour d'autres tâches lorsque le programme le souhaite.

Ces différents processeurs et moteurs matériels doivent cependant partager une ressource essentielle : la DRAM principale de la Jaguar. Le Motorola 68000, le GPU, le DSP, l'Object Processor, le Blitter ainsi que les différents moteurs DMA peuvent avoir besoin d'accéder à cette mémoire. La DRAM contient notamment le programme principal, les Object Lists, les images, les textures, les framebuffers, les données audio et les autres structures utilisées par le logiciel.

Cette mémoire partagée constitue à la fois une force et une contrainte de l'architecture. Elle facilite l'échange de données entre les différents composants puisqu'ils peuvent travailler sur des informations placées dans un espace commun. En revanche, plusieurs unités peuvent demander simultanément l'accès à la DRAM. Le système doit alors arbitrer ces demandes, ce qui produit de la contention et peut réduire la bande passante disponible pour certains processeurs.

Pour limiter cette dépendance à la mémoire partagée, le GPU et le DSP possèdent chacun leur propre RAM locale rapide. Cette mémoire est particulièrement adaptée au stockage du code exécuté fréquemment, des petites boucles critiques, des tables importantes et des données temporaires utilisées intensivement. Un programme performant cherche donc généralement à placer les noyaux de calcul essentiels dans ces mémoires locales plutôt que de faire continuellement exécuter le GPU ou le DSP depuis la DRAM.

Le fonctionnement graphique typique de la Jaguar repose sur une répartition du travail entre plusieurs unités plutôt que sur un processeur graphique unique exécutant l'intégralité d'un pipeline moderne. Le GPU peut commencer par effectuer les calculs de géométrie et préparer les commandes nécessaires au rendu. Dans un moteur 3D, il peut par exemple transformer des coordonnées, déterminer les limites de polygones et calculer les spans qui devront ensuite être dessinés.

Une fois ces informations préparées, le Blitter peut prendre en charge une grande partie du travail répétitif sur les pixels. Le GPU configure ses registres et lui demande de tracer, copier ou transformer des données dans des tampons placés en DRAM. Selon le moteur graphique utilisé, ces tampons peuvent être des framebuffers, des surfaces intermédiaires, des textures transformées ou des zones associées à un Z-buffer. Le Blitter permet ainsi de décharger le GPU et le 68000 d'une quantité importante de manipulations graphiques.

L'Object Processor intervient ensuite dans la construction de l'image effectivement affichée. À chaque ligne vidéo, il parcourt une Object List située en DRAM. Il détermine quels objets sont actifs pour la ligne courante, récupère leurs données graphiques et les compose dans un line buffer interne. Les objets peuvent correspondre à des Bitmaps, à des images redimensionnées ou à des structures de contrôle telles que des branchements et des interruptions GPU.

Cette organisation signifie que l'affichage ne nécessite pas obligatoirement un framebuffer unique contenant déjà toute l'image finale. L'Object Processor peut composer directement une ligne à partir de plusieurs objets différents. Dans un jeu 3D, il peut cependant aussi afficher un framebuffer préalablement produit par le GPU et le Blitter, puis y combiner éventuellement d'autres éléments graphiques. L'architecture autorise donc plusieurs stratégies de rendu.

Une fois la ligne construite, le bloc vidéo de TOM prend en charge son interprétation et sa conversion. Selon la configuration sélectionnée, les pixels peuvent notamment être représentés dans les formats CRY ou RGB. Le circuit vidéo effectue les conversions nécessaires, notamment du CRY vers une représentation RGB adaptée, puis produit les informations nécessaires à la sortie vidéo. La chaîne graphique peut donc être résumée comme une coopération entre calcul, rasterisation, composition des objets et génération du signal.

La partie audio suit une organisation comparable dans laquelle le travail est réparti entre plusieurs éléments de JERRY. Le DSP peut exécuter le programme chargé de traiter les données sonores, de décoder ou de générer certains sons et surtout de mélanger la musique et les effets sonores. Cette approche permet au logiciel de définir une grande partie de son moteur audio plutôt que de dépendre uniquement d'un générateur sonore possédant un nombre fixe de voix matérielles.

Après le traitement effectué par le DSP, les échantillons résultants sont transmis au système audio de JERRY, qui alimente le DAC par l'intermédiaire du chemin série prévu à cet effet. Le DSP peut ainsi construire en temps réel le flux sonore final à partir de plusieurs sources, puis fournir les données nécessaires à leur conversion en signal audio.

Un rendu typique sur Jaguar peut donc suivre une chaîne fonctionnelle dans laquelle le 68000 orchestre le programme, le GPU prépare la géométrie et les commandes, le Blitter effectue les opérations graphiques intensives dans la DRAM, l'Object Processor compose chaque ligne dans les line buffers et le bloc vidéo produit la sortie CRY/RGB. En parallèle, le DSP de JERRY mélange la musique et les effets avant d'alimenter le système de conversion audio. L'efficacité de la console dépend largement de la capacité du programme à faire travailler ces unités simultanément tout en limitant leurs conflits d'accès à la DRAM.

Horloges NTSC et PAL

La console Atari Jaguar utilise une horloge principale dont dépendent plusieurs de ses composants matériels. Dans une console NTSC, l'horloge système utilisée par les puces TOM et JERRY est proche de 26,59 MHz. Cette fréquence constitue une référence importante pour le fonctionnement des processeurs spécialisés et de plusieurs mécanismes internes de la machine. Il faut toutefois distinguer cette horloge système de la fréquence réellement reçue par le Motorola 68000.

Le Motorola 68000 fonctionne en effet à une fréquence correspondant approximativement à la moitié de l'horloge système, soit environ 13,295 MHz sur une Jaguar NTSC. Le GPU, le DSP et les différents moteurs matériels ne doivent donc pas être supposés fonctionner selon exactement le même rythme que le 68000. Cette différence fait partie de l'architecture de la console et intervient notamment dans l'estimation du temps disponible pour effectuer certains traitements pendant une ligne ou une trame vidéo.

Les consoles PAL utilisent une référence d'horloge légèrement différente de celle des machines NTSC. La différence ne se limite donc pas simplement à demander au même matériel d'afficher 50 images par seconde au lieu de 60. Les fréquences de référence et les paramètres de synchronisation vidéo sont adaptés au standard régional. Un logiciel qui cherche à contrôler précisément les timings doit ainsi tenir compte de la région de la console plutôt que de supposer que toutes les Jaguar possèdent exactement les mêmes valeurs temporelles.

Le système vidéo de la Jaguar est relativement flexible parce que sa temporisation repose sur des compteurs horizontaux et verticaux programmables. Les registres vidéo permettent de définir les différentes étapes du balayage : durée des lignes, périodes de synchronisation, début et fin de la zone visible ainsi que paramètres verticaux correspondants. Cette organisation permet au logiciel d'adapter la géométrie et la cadence de l'affichage dans les limites imposées par le matériel et par le standard vidéo utilisé.

Cette programmabilité permet de produire différentes résolutions et cadences d'affichage, généralement organisées autour des standards d'environ 60 Hz en NTSC et 50 Hz en PAL. Ces valeurs décrivent toutefois des familles de timings plutôt qu'une résolution fixe imposée par la Jaguar. Le programme configure les compteurs vidéo afin d'obtenir le mode d'affichage recherché tout en respectant les contraintes électriques et temporelles de la sortie vidéo.

Il n'existe donc pas une résolution matérielle unique de la Jaguar comparable à un écran qui fonctionnerait obligatoirement dans un seul mode. Des résolutions telles que 320 × 200, 320 × 240 ou 320 × 256 peuvent être utilisées selon la configuration choisie. Leur emploi dépend du logiciel, de la région et des timings vidéo programmés. Certaines résolutions sont naturellement mieux adaptées à un standard ou à une utilisation particulière, mais elles ne constituent pas à elles seules une définition absolue des capacités vidéo de la console.

Le logiciel peut également exploiter des modes utilisant de l'overscan. Dans ce cas, la zone affichée est étendue vers des parties du signal vidéo qui se trouvent normalement près des limites de l'écran ou en dehors de la zone visible conventionnelle. L'étendue réellement observable dépend alors également du téléviseur ou du moniteur utilisé, les appareils analogiques ne présentant pas tous exactement la même portion du signal.

La Jaguar permet également de travailler avec de l'entrelacement (interlacing). Au lieu de produire chaque trame de manière strictement progressive, un mode entrelacé peut organiser l'affichage en champs complémentaires. Cette technique peut servir à augmenter la résolution verticale apparente ou à produire certains modes vidéo particuliers, au prix des contraintes habituelles de l'entrelacement, notamment une stabilité visuelle différente de celle d'un affichage progressif.

Le choix d'une résolution ne dépend cependant pas uniquement des valeurs que le programmeur peut inscrire dans les registres de timing. La largeur des line buffers constitue une contrainte matérielle importante. L'Object Processor doit pouvoir construire les pixels d'une ligne dans ces tampons internes avant que le circuit vidéo ne les lise. Une résolution horizontale trop importante ou une configuration incompatible avec leur capacité ne peut donc pas être obtenue simplement en modifiant les compteurs vidéo.

Le pixel clock, ou horloge des pixels, impose également des limites concrètes. Il détermine le rythme auquel les pixels sont transmis pendant la portion visible de chaque ligne. La combinaison du pixel clock, des timings horizontaux, de la largeur disponible dans les line buffers et de la fréquence de balayage détermine les modes réellement exploitables. Toutes les combinaisons théoriques de largeur, de hauteur et de fréquence ne sont donc pas nécessairement réalisables ou utilisables.

Les résolutions de la Jaguar doivent ainsi être comprises comme des configurations logicielles du système vidéo plutôt que comme une liste de modes fixes semblable à celle de certaines autres architectures graphiques. Des formats comme 320 × 200, 320 × 240, 320 × 256, l'overscan ou l'entrelacement résultent de choix effectués en fonction des compteurs vidéo, de la région NTSC/PAL et des besoins du logiciel. Les véritables limites proviennent de la temporisation du signal, du pixel clock, des line buffers et de la bande passante disponible.

Pour un programme ou un émulateur Jaguar, il est donc préférable de reproduire le fonctionnement des compteurs horizontaux et verticaux programmables plutôt que de considérer la console comme une machine possédant uniquement quelques résolutions prédéfinies. Cette approche permet de représenter correctement les différences entre NTSC et PAL ainsi que les modes particuliers employés par certains logiciels, tout en respectant les contraintes physiques qui déterminent ce que le matériel peut réellement afficher.

Bus système et phrases 64 bits

L'architecture de la console Atari Jaguar accorde une grande importance à une unité de données appelée phrase. Dans la terminologie de la Jaguar, une phrase correspond exactement à 64 bits, soit 8 octets. Cette notion apparaît dans de nombreux composants de la machine, notamment dans l'Object Processor (OP) et le Blitter, ainsi que dans l'organisation des objets graphiques et de certaines données en mémoire. Il est donc important de ne pas confondre une phrase Jaguar avec un mot (word) de 16 bits ou un long (longword) de 32 bits.

La DRAM principale de la Jaguar est organisée de manière à favoriser les transferts de 64 bits et l'utilisation du mode page (page mode). Lorsqu'une série d'accès concerne des données situées dans une même page de DRAM, le contrôleur mémoire peut les traiter plus efficacement que lorsqu'il doit continuellement changer de page. Cette organisation est particulièrement avantageuse pour les circuits graphiques qui doivent lire de grandes quantités de données de manière régulière.

L'Object Processor et le Blitter sont justement conçus pour exploiter ces transferts sous forme de phrases. L'OP récupère notamment les descripteurs de l'Object List et les données graphiques en utilisant cette organisation de 64 bits, tandis que le Blitter peut traiter efficacement des blocs de données avec la même granularité. Pour ces composants, l'organisation des informations en mémoire influence donc directement les performances.

Les objets, les descripteurs et les données destinées aux opérations rapides doivent ainsi respecter les contraintes d'alignement prévues par leur type. Selon la structure concernée, il peut être nécessaire d'utiliser un alignement sur 8, 16 ou 32 octets. Une phrase simple possède naturellement une granularité de 8 octets, mais certaines structures composées de plusieurs phrases imposent ou recommandent un alignement supérieur. Un Bitmap Object et un Scaled Bitmap Object, par exemple, ne doivent pas nécessairement être placés selon exactement la même frontière d'alignement.

Le Motorola 68000 ne peut cependant pas exploiter directement une largeur de bus de 64 bits. Son bus de données externe est de 16 bits. Une phrase Jaguar de 64 bits représente donc quatre fois la largeur d'un transfert de données naturel du 68000. Pour lire ou écrire l'équivalent d'une phrase complète, le processeur doit effectuer plusieurs cycles de bus, typiquement plusieurs transferts de 16 bits.

Cette différence explique certaines précautions nécessaires lorsque le 68000 construit des structures destinées aux circuits 64 bits de la Jaguar. Une valeur qui apparaît comme une seule entité de 64 bits du point de vue de l'Object Processor ne peut pas nécessairement être créée par le 68000 en une seule opération atomique. Les différents mots qui la composent sont transférés séparément, ce qui peut également devenir important lorsqu'un coprocesseur est susceptible de lire simultanément la structure en cours de modification.

Le GPU et le DSP sont pour leur part des processeurs 32 bits. Leurs registres et leurs opérations principales manipulent donc naturellement des valeurs de cette largeur. Cela ne signifie toutefois pas que toute l'architecture mémoire de la Jaguar est limitée à 32 bits. Le Blitter et l'Object Processor peuvent exploiter la largeur de la DRAM et les transferts par phrases de 64 bits, ce qui leur permet d'obtenir un débit particulièrement intéressant pour les opérations graphiques correctement organisées.

La bande passante réellement obtenue ne dépend cependant pas uniquement de la largeur théorique des transferts. Elle varie également en fonction de l'ordre des adresses mémoire consultées. Des accès séquentiels ou organisés de manière à exploiter efficacement la DRAM peuvent être beaucoup plus rapides qu'une succession d'accès dispersés qui oblige le contrôleur mémoire à modifier fréquemment son état.

La page DRAM dans laquelle se trouvent les données joue notamment un rôle important. Lorsque plusieurs transferts successifs restent dans une même page, le page mode peut être exploité efficacement. À l'inverse, des changements fréquents de page introduisent des coûts supplémentaires. La disposition des textures, des Object Lists, des framebuffers et des autres données graphiques doit donc être pensée pour favoriser autant que possible des accès cohérents.

La bande passante dépend aussi des priorités d'accès au bus, du rafraîchissement de la DRAM et de la contention entre les différents composants. La mémoire principale est partagée : le 68000, le GPU, le DSP et les moteurs graphiques peuvent avoir besoin d'y accéder pendant des périodes proches. Le contrôleur doit alors arbitrer les demandes. À cela s'ajoutent les cycles nécessaires au rafraîchissement de la DRAM, qui font partie du fonctionnement normal de cette technologie de mémoire.

Il serait donc incorrect d'estimer les performances mémoire de la Jaguar uniquement en multipliant une largeur de 64 bits par une fréquence d'horloge. La bande passante pratique dépend du type d'accès, de l'alignement, de la localisation des données dans les pages, des priorités matérielles, du rafraîchissement et de l'activité simultanée des autres unités. Deux routines transférant la même quantité de données peuvent ainsi présenter des performances sensiblement différentes selon leur organisation mémoire.

La notion de byte order, ou ordre des octets, constitue également une source fréquente de confusion. Le Motorola 68000 est big-endian, c'est-à-dire qu'il place l'octet de poids fort d'une valeur multioctet à l'adresse la plus basse. Cependant, il ne suffit pas d'appliquer cette règle de manière naïve à toutes les structures 64 bits de la Jaguar. Les registres et descripteurs utilisés par l'Object Processor possèdent une disposition particulière des mots et des phrases qui doit être respectée lorsqu'ils sont préparés depuis le 68000.

Le cas de OLP (Object List Pointer) illustre particulièrement cette difficulté. Lorsqu'il est manipulé depuis le Motorola 68000, sa représentation doit respecter le word swapping indiqué par la documentation de la Jaguar. Les mots qui composent la valeur doivent donc être disposés dans l'ordre attendu par l'Object Processor, et pas simplement écrits selon une interprétation intuitive d'un entier multioctet.

Cette distinction entre endianness, largeur de bus et disposition interne des phrases est essentielle. Le fait que le 68000 soit big-endian ne décrit pas à lui seul la manière dont toutes les structures de TOM doivent apparaître en mémoire. Le programmeur doit tenir compte simultanément de la représentation du 68000, des transferts de 16 bits qu'il effectue, des phrases de 64 bits utilisées par les moteurs graphiques et des règles particulières de word swapping définies par Atari.

La notion de phrase de 64 bits constitue ainsi l'un des éléments centraux de l'architecture mémoire de la Jaguar. Pour exploiter efficacement la machine, il faut aligner correctement les structures, organiser les données afin de favoriser le page mode de la DRAM, limiter la contention et respecter la représentation particulière des données lorsqu'elles passent du monde 16 bits du bus du 68000 aux unités 32 bits ou 64 bits de TOM et de JERRY.

Motorola 68000

Le Motorola 68000 constitue le processeur généraliste principal de la console Atari Jaguar. Même si une grande partie de la puissance de calcul spécialisée de la machine provient du GPU, du DSP, du Blitter et de l'Object Processor, le 68000 joue un rôle essentiel dans le démarrage de la console, l'exécution de la logique générale du programme et la coordination de ces différents composants. Son architecture doit toutefois être utilisée en tenant compte du système de bus et de mémoire particulier de la Jaguar.

Le 68000 possède huit registres de données de 32 bits, nommés D0 à D7. Ils sont utilisés pour les opérations arithmétiques, logiques, les comparaisons, les déplacements de bits et le stockage temporaire de valeurs. À ceux-ci s'ajoutent huit registres d'adresse, A0 à A7, également utilisés pour manipuler des adresses et effectuer les différents modes d'adressage proposés par le processeur.

Le registre A7 possède une fonction particulière puisqu'il sert de pointeur de pile (Stack Pointer). Il indique l'emplacement courant de la pile utilisée notamment par les appels de sous-programmes, les retours, les interruptions et le stockage temporaire de certaines informations. Le processeur possède également le SR (Status Register), qui contient son état et ses indicateurs de condition, ainsi que le PC (Program Counter), qui indique l'adresse du code en cours d'exécution.

Sur la Jaguar, le Motorola 68000 utilise un espace d'adressage de 24 bits. Il peut donc référencer des adresses comprises dans un espace théorique de 16 Mio, de $000000 à $FFFFFF. Les différentes ressources de la console - RAM, ROM, cartouche, TOM, JERRY et autres registres matériels - sont réparties à l'intérieur de cet espace selon la cartographie mémoire de la Jaguar.

Une contrainte fondamentale du 68000 concerne l'alignement mémoire. Les accès portant sur un mot de 16 bits (word) ou un long de 32 bits (longword) doivent commencer à une adresse paire. Les accès à un octet peuvent être réalisés à une adresse paire ou impaire, mais ce n'est pas le cas des mots et des longs.

Si le processeur tente de lire ou d'écrire un mot ou un long à une adresse impaire, il provoque une exception Address Error. Le programmeur doit donc s'assurer que les structures contenant des valeurs de 16 ou 32 bits sont correctement alignées. Cette contrainte est particulièrement importante avec les structures matérielles de la Jaguar, dont certaines imposent en plus leurs propres exigences d'alignement en phrases ou en blocs plus grands.

Comme sur les autres systèmes utilisant le 68000, le démarrage repose sur des vecteurs placés au début de l'espace d'adressage. Les adresses $000000 et $000004 correspondent respectivement aux informations utilisées pour initialiser la pile et déterminer le point d'entrée du processeur lors d'un reset. Dans le contexte de la Jaguar, ces vecteurs deviennent pertinents à ces emplacements une fois la RAM correctement cartographiée et leur contenu chargé selon la séquence de démarrage prévue par le système.

Dans l'organisation générale d'un programme Jaguar, le 68000 convient particulièrement bien aux opérations de démarrage et d'initialisation. Il peut préparer les structures de données, configurer les composants matériels, charger du code dans les mémoires locales du GPU ou du DSP et lancer les différents coprocesseurs. Il constitue ainsi le processeur naturel pour établir l'état initial de la machine avant que les unités spécialisées commencent leurs traitements.

Il est également bien adapté à la logique générale du programme, à la gestion des états du jeu et aux opérations d'entrée-sortie. Le 68000 peut notamment traiter les événements généraux, coordonner les périphériques et décider des tâches qui doivent être confiées aux processeurs spécialisés. Il joue ainsi un rôle important d'orchestration, même lorsque les calculs graphiques ou audio intensifs sont exécutés ailleurs.

Il faut toutefois tenir compte du fait que le 68000 ne dispose pas d'un accès exclusif à la mémoire principale. Ses accès à la DRAM partagée peuvent entrer en interaction ou en concurrence avec ceux du GPU, du Blitter, de l'Object Processor et des autres unités utilisant le bus. Un code 68000 effectuant de nombreux accès mémoire peut donc contribuer à la contention et réduire les performances globales du système.

Une autre subtilité concerne les registres matériels accessibles sur un chemin de 16 bits. Même lorsqu'un registre interne de TOM, de JERRY ou d'un autre composant représente une valeur de 32 bits, une écriture effectuée par le 68000 peut être décomposée en deux cycles de bus de 16 bits. La valeur complète n'est donc pas nécessairement modifiée de façon atomique du point de vue des autres circuits.

Entre ces deux cycles, un autre composant matériel peut éventuellement observer un état intermédiaire, dans lequel seulement la moitié de la valeur de 32 bits a été remplacée. Cette particularité devient critique pour certains pointeurs ou registres de contrôle utilisés simultanément par les coprocesseurs. C'est notamment la raison pour laquelle certaines opérations sensibles sont préférablement confiées au GPU lorsqu'il peut effectuer l'écriture requise de manière atomique sur son propre chemin interne.

Le Motorola 68000 doit donc être considéré comme le processeur d'orchestration général de la Jaguar, plutôt que comme l'unique moteur de calcul de la console. Ses registres D0-D7, A0-A7, SR et PC, son espace d'adressage de 24 bits et ses règles d'alignement restent ceux de l'architecture 68000, mais son utilisation doit tenir compte des particularités de la Jaguar : DRAM partagée, contention du bus, coprocesseurs fonctionnant en parallèle et accès 32 bits parfois décomposés en deux opérations de 16 bits.

Ensemble d'instructions 68000

Catégorie Instructions
Transfert MOVE/MOVEA/MOVEQ/MOVEM/MOVEP, LEA, PEA, LINK, UNLK, EXG.
Arithmétique ADD, SUB, CMP et variantes, MULS/MULU, DIVS/DIVU, NEG/NEGX, CLR, EXT.
Logique/bit AND, OR, EOR, NOT, BTST, BCHG, BCLR, BSET.
Décalage ASL/ASR, LSL/LSR, ROL/ROR, ROXL/ROXR, SWAP.
Contrôle BRA, BSR, Bcc, DBcc, Scc, JMP, JSR, RTS, RTE, RTR, TRAP.
Système RESET, STOP, NOP, TAS, MOVE SR/CCR/USP.

Le 68000 original n'a ni cache ni MMU. Une boucle de polling agressive consomme le bus; préférer interruption ou travail local pendant GPU/DSP.

Carte mémoire au reset

Avant la première écriture a MEMCON1, une fenêtre ROM0 de 2 Mio est répétée dans les 16 Mio. Dans cette vue :

Adresse Description
$000000-$0FFFFF Bootstrap ROM/miroirs
$100000-$10FFFF Registres internes Tom
$110000-$113FFF Jerry
$114000-$117FFF Manettes de jeux/GPIO
$118000-$11AFFF DSP Jerry
$120000-$1FFFFF Bootstrap ROM/miroirs

Cette carte permet de démarrer avec différents CPU possibles. Le BIOS configure MEMCON1, sélectionne ROMHI et fait apparaître DRAM/cartouche. Un émulateur qui commence directement dans la carte finale peut rater les accès BIOS initiaux.

Carte mémoire ROMHI=1

Adresse Description
$000000-$1FFFFF DRAM principale 2 Mio sur console, dans zone DRAM0
$200000-$7FFFFF Reste zone DRAM/réserve selon implémentation
$800000-$DFFFFF ROM1 cartouche, fenêtre maximale 6 Mio
$E00000-$FFFFFF ROM0 bootstrap et espaces internes

Sous ROMHI=1, registres internes sont a `$F00000-$F1FFFF`. Le bootstrap physique occupe une petite partie de ROM0 mais se répète/partage avec décodage ASIC. La carte générique du chipset prévoit deux banques DRAM de 4 Mio; la console n'en installe que 2 Mio au total.

Avec ROMHI=0, ROM/cartouche/DRAM permutent vers le bas et le premier chiffre des registres documentés devient souvent `$1` au lieu de `$F`. Les logiciels console ne doivent pas changer cette configuration après le démarrage.

MEMCON1, MEMCON2 et configuration

La console Atari Jaguar utilise les registres MEMCON1 et MEMCON2 pour configurer plusieurs caractéristiques fondamentales de son système mémoire. Ces registres déterminent notamment la manière dont certains espaces mémoire sont présentés aux processeurs, la largeur des accès ainsi que différents paramètres de temporisation de la ROM, de la DRAM et des entrées-sorties. Leur configuration se situe donc à un niveau très bas de l'architecture matérielle : une valeur incorrecte peut empêcher la machine d'accéder normalement à certaines parties de sa mémoire.

Le registre MEMCON1, situé à l'adresse $F00000, contient plusieurs champs de configuration. Le bit 0, appelé ROMHI, intervient dans la disposition de la ROM dans l'espace d'adressage. Sa valeur influence la manière dont la zone ROM est présentée au système. Modifier ce bit sans tenir compte de la configuration matérielle peut donc changer l'emplacement ou l'accessibilité de la ROM attendue par le programme.

Les bits 1 et 2 de MEMCON1 définissent la largeur du chemin utilisé pour la ROM. Selon leur combinaison, la ROM peut être configurée pour une largeur de 8, 16, 32 ou 64 bits. Cette information doit correspondre à l'organisation matérielle réellement utilisée. Il ne s'agit pas simplement d'une option permettant d'accélérer arbitrairement les accès : le contrôleur mémoire doit connaître la largeur correcte pour effectuer les cycles de bus conformément au périphérique auquel il accède.

Les bits 3 et 4 règlent la vitesse ou le timing des accès ROM. Ils déterminent les temporisations employées lors des cycles destinés à la mémoire morte. Une ROM suffisamment rapide peut fonctionner avec des paramètres plus agressifs, tandis qu'un périphérique plus lent exige davantage de temps. Une configuration trop lente gaspille des cycles, alors qu'une configuration trop rapide peut conduire à des lectures incorrectes ou instables.

Les bits 5 et 6 concernent les timings de la DRAM. Comme pour la ROM, ces paramètres contrôlent la manière dont le matériel synchronise ses accès à la mémoire dynamique. Ils doivent correspondre aux caractéristiques de la mémoire réellement installée dans la console. Une mauvaise temporisation peut provoquer des lectures ou des écritures erronées et donc entraîner des corruptions difficiles à diagnostiquer.

Le bit 7, associé à FASTROM, est lié à un mode ou à un test d'accès rapide à la ROM. Il fait partie des paramètres bas niveau du contrôleur mémoire et ne doit pas être activé arbitrairement dans l'espoir d'améliorer les performances. Son comportement doit être interprété dans le contexte de la configuration matérielle prévue par Atari et des caractéristiques de la ROM utilisée.

Les bits 11 et 12 de MEMCON1 contrôlent la vitesse des entrées-sorties (I/O). Ils permettent au contrôleur mémoire d'appliquer les temporisations appropriées aux cycles destinés aux périphériques concernés. Là encore, le réglage influence directement la durée des accès : une valeur inadéquate peut provoquer des problèmes avec le matériel ou imposer inutilement des cycles plus longs.

Le bit 14, appelé CPU32, intervient dans la configuration du comportement du bus vis-à-vis du processeur et des accès 32 bits. Il fait partie des paramètres qui doivent correspondre à l'architecture matérielle réelle de la machine. Il ne faut donc pas interpréter ce bit comme une simple indication abstraite signifiant que le Motorola 68000 devient un processeur 32 bits ; il contrôle un aspect de l'interface mémoire et du bus.

Tous les bits de MEMCON1 ne possèdent pas une fonction programmable destinée au logiciel. Les bits réservés doivent rester à zéro. Écrire des valeurs arbitraires dans ces positions peut produire un comportement non documenté ou dépendant de la révision du silicium. Lorsqu'un logiciel doit manipuler ce registre, il est donc essentiel de construire sa valeur uniquement à partir des champs officiellement définis.

Atari indique en outre que MEMCON1 ne doit normalement pas être modifié sur une console standard. Le matériel et le BIOS fournissent déjà une configuration correspondant aux composants réellement installés. Un jeu ou un programme ordinaire n'a généralement aucune raison de reprogrammer ces paramètres. La présence du registre dans l'espace d'adressage ne signifie donc pas qu'il soit destiné à être modifié librement pendant l'exécution d'un logiciel.

Le registre MEMCON2, situé à l'adresse $F00002, complète cette configuration. Il contrôle notamment des paramètres concernant la largeur et l'organisation en banques de la DRAM, ainsi que d'autres caractéristiques de temporisation du système mémoire. Certains détails peuvent dépendre du silicium ou de sa révision, ce qui renforce encore l'importance de ne pas remplacer sans nécessité les valeurs déterminées pour la machine.

Au démarrage, le BIOS de la Jaguar fournit les valeurs appropriées pour MEMCON1 et MEMCON2. Ces valeurs correspondent à la configuration matérielle que la ROM de démarrage s'attend à trouver sur la console. Pour un logiciel fonctionnant dans l'environnement normal de la Jaguar, la stratégie la plus sûre consiste donc à conserver cette configuration plutôt qu'à tenter de recalculer ou d'optimiser les timings.

Une erreur dans MEMCON1 ou MEMCON2 peut avoir des conséquences beaucoup plus graves qu'une simple diminution des performances. Une mauvaise configuration de la cartographie ou de la largeur du bus peut rendre la ROM ou la RAM inaccessible, donnant l'impression qu'une région mémoire a disparu. Des timings incorrects peuvent également ralentir fortement les cycles, retourner des données incorrectes ou provoquer des corruptions lors des lectures et des écritures.

Ces deux registres doivent par conséquent être considérés comme des paramètres de configuration matérielle fondamentale, principalement établis au démarrage par le BIOS. Ils sont indispensables pour comprendre l'architecture mémoire de la Jaguar ou pour réaliser une émulation fidèle, mais un logiciel destiné à une console standard devrait respecter la recommandation d'Atari et éviter de les modifier, sauf lorsqu'un environnement matériel particulier exige explicitement une autre configuration.

RAM principale

La console Atari Jaguar dispose de 2 Mio de DRAM principale partagée entre ses différents processeurs et circuits spécialisés. Cette mémoire constitue l'espace de travail général de la machine : elle peut contenir le code exécuté par le Motorola 68000, les Object Lists utilisées par l'Object Processor, les images et textures, différents tampons graphiques, les données audio, les piles d'exécution ainsi que les variables et autres données nécessaires aux programmes. La quantité de mémoire disponible doit donc être répartie entre de nombreux usages concurrents.

Une caractéristique fondamentale de l'architecture de la Jaguar est l'absence de VRAM séparée exclusivement réservée au système graphique. Les données utilisées pour produire l'image résident dans la même DRAM principale que celles employées par les processeurs et les autres unités de la console. Le Motorola 68000, le GPU, le Blitter, l'Object Processor et les autres circuits susceptibles d'accéder à cette mémoire doivent ainsi partager une ressource commune.

Cette architecture signifie que les accès nécessaires à la vidéo peuvent entrer en concurrence avec les accès des CPU et des autres moteurs matériels. Lorsque l'Object Processor doit récupérer les données d'un objet pendant que le GPU ou le 68000 souhaite accéder à la DRAM, tous ne peuvent pas nécessairement obtenir immédiatement la bande passante maximale. Des phénomènes de contention mémoire peuvent alors provoquer des attentes et réduire les performances effectives des processeurs.

Pour cette raison, les performances de la Jaguar dépendent fortement de l'organisation physique des données en mémoire. Il est avantageux de disposer les informations en tenant compte des pages de DRAM, afin de favoriser des séries d'accès restant dans une même page plutôt que de provoquer continuellement des changements. Les données graphiques utilisées sous forme de phrases de 64 bits doivent également être correctement alignées pour permettre aux circuits spécialisés d'effectuer leurs transferts dans de bonnes conditions.

Il faut également éviter autant que possible une alternance défavorable entre les banques de mémoire. Une disposition qui oblige le matériel à passer constamment d'une banque ou d'une page à une autre peut introduire des pénalités supplémentaires et gaspiller une partie de la bande passante disponible. Sur Jaguar, l'organisation des structures, des textures et des tampons n'est donc pas uniquement une question de commodité logicielle : elle peut avoir une influence directe sur les performances du système.

La présence d'un framebuffer complet n'est par ailleurs pas obligatoire pour produire une image. L'Object Processor est capable de parcourir une Object List et de récupérer directement en mémoire les différents objets nécessaires à chaque ligne. Il peut ainsi composer l'affichage à partir de plusieurs Bitmaps, sprites ou autres objets sans qu'une image complète ait préalablement été rendue dans un framebuffer unique. Cette approche peut économiser une quantité importante de RAM et de bande passante pour certains jeux essentiellement basés sur des objets 2D.

Un framebuffer devient toutefois particulièrement utile lorsque le programme réalise du rendu 3D ou produit une image calculée pixel par pixel avant son affichage. Dans ce cas, il est fréquent de conserver un tampon contenant l'image terminée ou en cours de construction. L'utilisation d'un double buffering demande deux tampons couleur : pendant que l'un est présenté à l'écran, le moteur graphique peut construire l'image suivante dans l'autre, puis échanger leurs rôles à la trame suivante.

À ces tampons couleur peut s'ajouter un Z-buffer, destiné à mémoriser la profondeur des pixels pendant le rendu 3D. L'utilisation simultanée de deux framebuffers et d'un Z-buffer peut donc consommer rapidement une part importante des seulement 2 Mio disponibles. Plus la résolution et la profondeur des pixels augmentent, plus cette consommation devient importante et laisse moins d'espace pour le code, les textures, les objets, l'audio et les autres données du jeu.

À titre d'exemple, un framebuffer de 320 × 240 pixels en 16 bits par pixel contient 76 800 pixels. À raison de deux octets par pixel, il nécessite 153 600 octets de mémoire. Deux tampons couleur de cette taille occupent donc 307 200 octets.

Si l'on ajoute un Z-buffer de 16 bits possédant également une résolution de 320 × 240 pixels, celui-ci nécessite 153 600 octets supplémentaires. L'ensemble constitué de deux tampons couleur de 16 bits et d'un Z-buffer de 16 bits représente donc environ 460 800 octets. Cela correspond à une part substantielle des 2 Mio de RAM de la Jaguar avant même d'avoir chargé les textures, les données audio, le code et les autres ressources nécessaires au jeu.

La gestion de la RAM principale constitue ainsi un aspect essentiel de la programmation de la Jaguar. Le développeur doit choisir entre la composition directe par l'Object Processor et l'utilisation de framebuffers lorsque ceux-ci sont nécessaires, tout en organisant soigneusement les données pour limiter la contention. L'alignement des phrases, la disposition dans les pages et les banques de DRAM ainsi que la taille des buffers graphiques ont tous une influence directe sur la quantité de mémoire disponible et sur les performances de la console.

ROM de démarrage et authentification

Lors de la mise sous tension de la console Atari Jaguar, le programme contenu dans la ROM de démarrage, généralement appelé BIOS, prend le contrôle de la machine. Son rôle ne consiste pas simplement à transférer immédiatement l'exécution vers la cartouche. Il commence par effectuer différentes opérations d'initialisation du matériel, notamment la configuration de MEMCON, c'est-à-dire des registres participant au contrôle et à l'organisation des accès mémoire. Cette étape place la console dans un état suffisamment cohérent pour poursuivre la séquence de démarrage.

Le BIOS prend également en charge la présentation visuelle du démarrage de la Jaguar, avec notamment le logo et l'animation associés à la console. Pendant cette séquence, il effectue parallèlement les opérations nécessaires pour déterminer si la cartouche insérée peut être considérée comme valide et autorisée à être exécutée. Le démarrage d'un jeu commercial implique donc une véritable procédure de vérification et non un simple saut vers une adresse fixe de la ROM de la cartouche.

Une partie importante de cette procédure fait intervenir le GPU de TOM. Le BIOS lui confie un traitement destiné à effectuer l'authentification et la vérification des données de la cartouche. Le GPU exécute alors le code et les calculs prévus par la procédure de démarrage. Le résultat attendu de ce mécanisme est associé à la valeur particulière $03D0DEAD, qui intervient comme valeur de référence dans le processus permettant au BIOS de décider si la vérification a réussi.

Pour une cartouche commerciale officielle, les données présentes dans la ROM doivent avoir été préparées de manière à satisfaire cette procédure. Elles doivent donc contenir les informations signées ou validées selon le processus d'authentification employé par Atari. Cette vérification faisait partie du mécanisme permettant à Atari de contrôler l'exécution normale des logiciels distribués sur cartouche. Une image contenant simplement du code Jaguar valide n'est donc pas nécessairement suffisante pour franchir la séquence d'authentification du BIOS original.

Il est important de préciser que cette vérification n'est pas un simple checksum additif placé dans l'en-tête de la cartouche. On ne peut donc pas reproduire fidèlement le mécanisme en additionnant quelques octets ou mots de la ROM puis en comparant le résultat à une valeur stockée dans un champ d'en-tête. La procédure implique le BIOS, le GPU et les données préparées conformément au système d'authentification de la Jaguar.

Le comportement exact peut également varier selon la révision et la région du BIOS. Toutes les consoles Jaguar ne possèdent pas nécessairement une ROM de démarrage strictement identique : différentes versions régionales ou révisions du BIOS peuvent présenter des différences dans leur code, leur séquence de démarrage ou certains détails du processus. Un programme ou un émulateur qui cherche à reproduire précisément le démarrage doit donc tenir compte de la ROM réellement utilisée plutôt que de considérer qu'il n'existe qu'un BIOS universel.

Les environnements de développement ne sont par ailleurs pas obligés de suivre exactement le même chemin qu'une cartouche commerciale démarrant sur une console standard. Les systèmes destinés au développement disposent de leurs propres mécanismes permettant de charger et d'exécuter du code. De même, les cartouches modernes, les solutions homebrew et les BIOS alternatifs peuvent employer d'autres chemins de chargement afin de permettre l'exécution de logiciels qui ne passent pas nécessairement par la procédure commerciale originale d'Atari.

Cette distinction est particulièrement importante dans un émulateur Jaguar. Pour faciliter le lancement de programmes de développement, de homebrews ou d'images ne possédant pas les informations d'authentification originales, l'émulateur peut proposer une option permettant de contourner (bypass) la vérification du BIOS. Dans ce mode, le programme peut être chargé ou démarré sans reproduire toute la procédure d'authentification d'une console réelle.

Un mode d'émulation visant la fidélité matérielle doit toutefois adopter une approche différente. Il doit permettre au véritable code du BIOS de s'exécuter, reproduire correctement les registres et le matériel qu'il utilise et respecter le dialogue entre le BIOS et le GPU pendant l'authentification. Il ne suffit pas que l'émulateur déclare artificiellement la cartouche valide : la séquence de démarrage, les calculs GPU et les échanges matériels doivent se comporter comme sur la Jaguar réelle. Cette distinction entre un mode pratique avec bypass et un mode fidèle est essentielle pour tester correctement les BIOS, les cartouches commerciales et les particularités du processus de démarrage de la console.

TOM : Vue générale

Tom couvre `$F00000-$F0FFFF` :

Adresse Description
$F00000-$F000FF Configuration, vidéo, OP, interruptions et minuteries
$F00400-$F007FF Color Look-Up Tables
$F00800... Line buffers via vues internes/externes selon alias
$F02000-$F021FF GPU contrôle/registres
$F02200-$F022FF Blitter
$F03000-$F03FFF RAM locale GPU, 4 Kio
$F08800-$F08D9F line buffer A, accès 32 bits
$F09000-$F0959F Line buffer B
$F09800-$F09D9F Line buffer sélectionné
$F0B000-$F0BFFF Alias RAM GPU 32 bits

Les plages exactes et largeurs doivent venir du register list. Plusieurs vues existent pour adapter bus d'entrée/sorties 16 bits et chemins internes 32/64 bits.

Registres vidéo et minuterie

Registre Description
$F00004 HC Compteur horizontal
$F00006 VC Compteur vertical
$F00008 LPH Latch position H
$F0000A LPV Latch position V
$F00020 OLP Pointeur object list
$F00026 OBF Drapeau/reprise Object Processor
$F00028 VMODE Activation et mode pixel
$F0002A BORD1 Couleur bordure, partie 1
$F0002C BORD2 Couleur bordure, partie 2
$F0002E HP Période horizontale
$F00030 HBB Début blank horizontal
$F00032 HBE Fin blank horizontal
$F00034 HS Synchro horizontale
$F00036 HVS Synchro H/V
$F00038 HDB1 Début affichage horizontal 1
$F0003A HDB2 Début affichage horizontal 2
$F0003C HDE Fin affichage horizontal
$F0003E VP Période verticale
$F00040 VBB Début blank vertical
$F00042 VBE Fin blank vertical
$F00044 VS Synchro verticale
$F00046 VDB Début affichage vertical
$F00048 VDE Fin affichage vertical
$F0004A VEB Equalisation début
$F0004C VEE Equalisation fin
$F0004E VI Ligne d'interruption vidéo
$F00050/$52 PIT Prescaler/diviseur
$F00054 HEQ Equalisation horizontale
$F00058 BG couleur d'arrière-plan du line buffer

Les compteurs utilisent des demi-lignes/horloges vidéo selon champ. Reprendre les tables d'initialisation NTSC/PAL officielles; une valeur "320" n'est pas posée directement dans HP.

Modes couleur CRY, RGB et direct

Le système vidéo de la console Atari Jaguar peut manipuler plusieurs représentations de couleur. Le registre VMODE détermine notamment la manière dont les pixels physiques contenus dans le line buffer sont interprétés et traduits avant d'être envoyés vers la sortie vidéo. Selon les bits configurés dans ce registre et la combinaison de modes sélectionnée, la Jaguar peut fonctionner notamment en CRY16, en RGB24 ou dans des modes directs tels que DIRECT16/RGB16. Il faut donc distinguer le format des données fournies par les objets de l'Object Processor du format finalement produit par le circuit vidéo.

Le format CRY16 est l'un des formats caractéristiques de la Jaguar. Chaque pixel y est représenté sur 16 bits, mais ces bits ne correspondent pas simplement à une répartition classique rouge-vert-bleu. Le format décompose plutôt la couleur en informations C, R et Y : C et R représentent les composantes de chrominance utilisées pour définir la teinte, tandis que Y représente la luminance ou intensité lumineuse. Cette organisation permet notamment de modifier l'intensité d'une couleur sans nécessairement devoir recalculer toutes ses composantes RGB.

Les valeurs CRY ne sont cependant pas envoyées telles quelles à un affichage RGB. Le circuit vidéo de TOM effectue matériellement la conversion du CRY vers une représentation RGB de 24 bits destinée à la génération de la sortie vidéo. Le logiciel peut ainsi travailler avec des pixels CRY16 compacts tandis que le matériel se charge de leur transformation finale. Ce mécanisme explique pourquoi le format CRY occupe une place importante dans l'architecture graphique de la Jaguar.

Le mode RGB16 représente également chaque pixel sur 16 bits, mais utilise une répartition compacte des composantes de couleur RGB. Les informations de rouge, de vert et de bleu doivent donc partager les 16 bits disponibles, ce qui offre moins de précision par composante qu'une représentation RGB sur 24 bits. En contrepartie, un pixel RGB16 consomme moins de mémoire et nécessite moins de bande passante qu'un pixel RGB24.

Le format RGB24 permet de disposer d'une représentation plus précise des composantes rouge, verte et bleue. Dans l'architecture de la Jaguar, son traitement utilise cependant un mot ou chemin de données de 32 bits par pixel. Les 24 bits nécessaires à la couleur sont transportés à l'intérieur de cette organisation de 32 bits, tandis que l'octet restant est inutilisé ou peut servir à des informations de commande selon le contexte matériel. Il ne faut donc pas conclure qu'un pixel manipulé sur un chemin de 32 bits représente nécessairement quatre composantes de couleur de 8 bits.

Le format des objets traités par l'Object Processor peut être différent du format physique utilisé pour la sortie. Les objets utilisant des profondeurs de 1, 2, 4 ou 8 bits par pixel sont des objets indexés : la valeur contenue dans chaque pixel sert d'indice dans la CLUT (Color Look-Up Table). L'Object Processor combine cet indice avec les paramètres de palette de l'objet afin d'obtenir une couleur physique de 16 bits, qui peut ensuite être placée dans le line buffer.

Cette utilisation de la CLUT permet de représenter les images avec très peu de mémoire. Un objet 1 bpp ne possède que deux valeurs possibles par pixel, tandis qu'un objet 8 bpp peut représenter jusqu'à 256 indices avant prise en compte de l'organisation de la palette. Dans tous ces cas, les pixels ne contiennent pas directement leur couleur physique complète : celle-ci est obtenue par la consultation de la CLUT.

Les objets utilisant une profondeur de 16 bits par pixel fonctionnent différemment. Leur valeur est considérée comme une couleur directe, de sorte qu'il n'est pas nécessaire de passer par la CLUT pour convertir un indice en couleur physique. Cette distinction entre les formats indexés de faible profondeur et le mode direct 16 bits est importante lors de la construction des Bitmaps et de la configuration de leurs champs DEPTH et de palette.

L'Object Processor possède également un mode permettant de traiter des objets en 24/32 bits par pixel. Dans ce cas, la quantité de données nécessaire pour chaque pixel est beaucoup plus importante et le matériel produit typiquement un pixel par cycle. Ce format permet d'utiliser des informations de couleur plus riches, mais il ne bénéficie pas de toutes les capacités des formats plus courants dans les mêmes conditions.

Une limitation notable concerne notamment le redimensionnement des objets 24/32 bpp. Le mécanisme des Scaled Bitmaps de l'Object Processor ne fonctionne pas correctement dans tous les cas avec ces profondeurs, et certaines combinaisons, en particulier lorsque l'échelle s'éloigne du rapport 1:1, peuvent produire des résultats incorrects ou déformés. Il faut donc éviter de supposer qu'un objet qui fonctionne normalement en 24/32 bpp sans redimensionnement pourra être agrandi ou réduit de la même manière qu'un Bitmap de profondeur inférieure.

L'architecture de l'Object Processor permet par ailleurs à des objets de profondeurs différentes de coexister dans une même Object List. Une scène peut donc contenir, par exemple, des objets indexés à faible profondeur, des Bitmaps directs de 16 bits et d'autres objets utilisant une profondeur supérieure. L'OP interprète chaque objet selon les paramètres inscrits dans son propre descripteur et produit les pixels physiques nécessaires dans le line buffer.

Cette coexistence n'est toutefois pas totalement indépendante de la configuration vidéo globale. Certaines combinaisons restent soumises aux restrictions imposées par le mode de sortie sélectionné dans VMODE et par les chemins matériels utilisés pour convertir le contenu du line buffer. La profondeur d'un objet, le recours éventuel à la CLUT et le mode de couleur final sont donc trois notions liées mais distinctes. Pour programmer correctement l'affichage de la Jaguar, il faut tenir compte à la fois du format de chaque objet, du format physique écrit dans le line buffer et de la traduction finale sélectionnée par VMODE.

CLUT et Line buffers

La puce TOM de la console Atari Jaguar possède des ressources spécialisées permettant à l'Object Processor (OP) de convertir les données graphiques des objets et de construire progressivement les lignes destinées à l'affichage. Parmi ces ressources figurent la CLUT (Color Look-Up Table) et deux line buffers. La CLUT permet principalement de transformer des indices de couleur en valeurs de pixels physiques, tandis que les line buffers servent de zones de travail temporaires dans lesquelles l'Object Processor compose une ligne complète avant son envoi au circuit vidéo.

La Jaguar dispose de deux ensembles de CLUT de 256 entrées, que l'on peut considérer selon leur organisation logique et physique. Cette organisation est liée à la capacité du matériel à traiter deux pixels en parallèle. Une entrée de palette associe un indice numérique à une couleur physique utilisée par le système vidéo. Les images utilisant peu de bits par pixel peuvent ainsi conserver des données très compactes en mémoire : plutôt que de stocker une couleur complète pour chaque pixel, elles contiennent des indices qui servent à retrouver les couleurs correspondantes dans la CLUT.

Pour les objets utilisant une faible profondeur de couleur, l'Object Processor combine l'index contenu dans le pixel avec un offset de palette défini dans le descripteur de l'objet. Cette méthode permet à plusieurs objets d'utiliser différentes parties de la CLUT tout en conservant des pixels codés sur un petit nombre de bits. Un objet peut ainsi employer une sous-palette particulière sans qu'il soit nécessaire de modifier les valeurs de ses pixels en mémoire.

La présence de deux chemins permettant le traitement parallèle des pixels impose cependant une précaution lors de la modification de la palette. Lorsque le matériel expose les deux moitiés de la CLUT séparément, le programme doit mettre à jour les deux moitiés de manière cohérente. Une palette dont une moitié contient les nouvelles valeurs alors que l'autre contient encore les anciennes peut produire des couleurs différentes selon le chemin utilisé pour le pixel. Les deux parties doivent donc rester synchronisées lorsque l'on souhaite obtenir une palette uniforme.

En plus de la CLUT, TOM possède deux line buffers, chacun capable de contenir approximativement 360 pixels de 32 bits. Ces mémoires ne servent pas à conserver une image complète. Elles constituent plutôt deux tampons temporaires permettant de préparer et de transmettre alternativement les lignes de l'image. Cette organisation évite que l'Object Processor et le circuit vidéo aient constamment besoin d'accéder au même tampon au même instant.

Les deux line buffers fonctionnent selon un principe d'alternance, comparable à un petit mécanisme de double buffering appliqué à une seule ligne. Pendant que l'un des buffers est lu par le circuit vidéo afin de produire la ligne actuellement envoyée vers l'affichage, l'Object Processor peut remplir l'autre buffer avec les pixels de la ligne suivante. Au changement de ligne, leurs rôles peuvent être inversés : celui qui vient d'être préparé devient disponible pour la sortie vidéo tandis que l'autre peut être réutilisé pour la composition suivante.

Les line buffers stockent les pixels physiques produits après l'interprétation des objets, notamment dans les formats correspondant aux données vidéo 16 ou 24 bits. Ils constituent donc l'étape intermédiaire entre les données graphiques décrites par l'Object List et le signal d'image produit par le sous-système vidéo. Un objet indexé peut, par exemple, être lu dans une faible profondeur, converti par l'intermédiaire de la CLUT, puis représenté dans le line buffer sous la forme physique attendue pour l'affichage.

La construction d'une ligne commence normalement par l'arrière-plan, qui fournit son contenu initial. Celui-ci établit les pixels de base sur lesquels les autres objets peuvent ensuite être composés. À mesure que l'Object Processor parcourt l'Object List, les Bitmaps et autres objets actifs pour cette ligne viennent modifier le contenu du line buffer correspondant.

Cette modification peut prendre la forme d'un remplacement direct : le pixel produit par un objet remplace alors celui qui était déjà présent dans le line buffer. Mais l'Object Processor peut également effectuer des opérations de type RMW (Read-Modify-Write). Dans ce cas, il lit la valeur déjà présente, applique le traitement prévu avec les nouvelles données, puis écrit le résultat. Ce mécanisme permet d'effectuer des compositions plus élaborées qu'un simple écrasement systématique du pixel précédent.

Il est important de ne pas confondre ces deux line buffers avec un éventuel système de double framebuffer utilisé par un jeu. Dans un double buffering classique, deux images complètes sont généralement conservées en mémoire : l'une est affichée pendant que l'autre est construite. Les line buffers internes de TOM ont une fonction totalement différente. Chacun ne contient qu'une seule ligne de pixels, et non une image entière.

Les deux buffers changent continuellement de rôle au rythme du balayage vidéo. Pendant qu'une ligne préparée dans l'un est consommée par le circuit d'affichage, la suivante est construite dans l'autre. Ils constituent donc une partie interne du pipeline vidéo de TOM et non les deux pages graphiques complètes d'un jeu. Un programme peut parfaitement utiliser ses propres framebuffers en DRAM tout en laissant l'Object Processor employer automatiquement ses deux line buffers pour composer, ligne après ligne, l'image effectivement envoyée vers la sortie vidéo.

Object Processor

L'Object Processor (OP) est l'un des principaux circuits graphiques de la puce TOM de la console Atari Jaguar. Son rôle consiste à construire l'affichage ligne par ligne à partir d'une Object List, c'est-à-dire une liste chaînée de descripteurs placée en DRAM. Contrairement à un système dans lequel le processeur principal doit recopier lui-même chaque sprite dans le framebuffer, l'Object Processor parcourt automatiquement cette liste et détermine quels objets doivent contribuer à la ligne vidéo actuellement générée.

Pour chaque ligne de l'écran, l'Object Processor commence donc à parcourir la liste chaînée. Il examine les descripteurs afin de déterminer quels objets sont actifs pour la ligne courante. Lorsqu'un objet graphique doit être affiché, l'OP lit ses données en mémoire sous forme de phrases de 64 bits, récupère les pixels nécessaires, puis les écrit dans le line buffer. Ce tampon de ligne contient progressivement les pixels qui serviront à produire la ligne vidéo correspondante.

L'Object Processor reconnaît directement cinq types matériels d'objets. Le type 0 correspond au Bitmap ordinaire, tandis que le type 1 représente le Scaled Bitmap, c'est-à-dire un Bitmap pouvant être redimensionné. Le type 2 est le GPU Interrupt Object, qui permet d'interrompre le GPU pendant le parcours de la liste. Le type 3 correspond au Branch Object, utilisé pour effectuer des branchements conditionnels à l'intérieur de l'Object List. Enfin, le type 4 est le Stop Object, qui marque la fin du parcours de la liste.

Un Bitmap non redimensionné, de type 0, utilise deux phrases de 64 bits pour son descripteur. Une phrase occupant 8 octets, son descripteur représente donc 16 octets au total. Il doit être placé avec un alignement de 16 octets. Cet alignement doit être respecté lors de la construction de l'Object List afin que l'Object Processor puisse récupérer correctement les phrases composant le descripteur.

Le Scaled Bitmap, de type 1, nécessite davantage d'informations puisqu'il doit également décrire ses paramètres de redimensionnement. Son descripteur utilise donc trois phrases de 64 bits, soit 24 octets de données. Malgré cette taille de 24 octets, la recommandation est de faire commencer le descripteur sur une adresse alignée sur 32 octets. Il faut ainsi distinguer la taille réelle du descripteur de la contrainte ou recommandation concernant son adresse de départ.

L'Object List fonctionne comme une liste chaînée grâce aux champs de liaison contenus dans les objets. Ces liens ne contiennent toutefois qu'une partie de l'adresse complète. Leur encodage permet de référencer des objets à l'intérieur de la même fenêtre mémoire de 4 Mio. La construction de la liste doit donc tenir compte de cette limitation : il ne faut pas considérer le champ LINK comme un pointeur entièrement libre permettant de relier arbitrairement des descripteurs placés n'importe où dans tout l'espace d'adressage de la Jaguar.

Une autre particularité fondamentale de l'Object Processor est qu'il ne se contente pas de lire les descripteurs. Pendant leur traitement, il réécrit certains champs directement dans l'Object List en DRAM. Pour un Bitmap, le champ DATA est avancé afin de suivre la progression dans les données graphiques, tandis que HEIGHT est diminué à mesure que les lignes de l'objet sont consommées. Le descripteur représente donc en partie un état de travail que l'OP fait évoluer pendant la génération de l'image.

Dans le cas d'un Scaled Bitmap, le même principe s'applique, mais un état supplémentaire doit être pris en compte. Le champ REMAINDER est modifié par l'Object Processor au cours du redimensionnement vertical. Cette valeur sert à l'accumulation qui détermine quand une nouvelle ligne de l'image source doit être utilisée, répétée ou sautée. À la fin du traitement, DATA, HEIGHT et REMAINDER peuvent donc ne plus contenir les valeurs qui avaient été placées initialement dans le descripteur.

Cette capacité d'écriture impose que l'Object List soit placée dans une mémoire accessible en écriture. Elle ne peut pas être considérée comme une simple table constante que l'OP ne ferait que consulter. Les descripteurs doivent être installés dans de la RAM writable, puisque le matériel doit pouvoir y mettre à jour ses informations de progression pendant le traitement des objets.

Avant la trame suivante, le programme doit normalement restaurer les champs que l'Object Processor a consommés ou modifiés. Pour les Bitmaps, cela concerne notamment DATA et HEIGHT; pour les Scaled Bitmaps, il faut également remettre REMAINDER dans l'état approprié. Les autres paramètres nécessaires à l'animation, comme les positions ou certains liens, peuvent ensuite être mis à jour selon les besoins avant que l'OP ne recommence à parcourir la liste.

Il existe toutefois une exception volontaire à cette restauration systématique. Un programme peut choisir d'exploiter la consommation progressive des descripteurs comme mécanisme d'animation ou de contrôle. Dans ce cas, certains champs modifiés par l'Object Processor sont intentionnellement conservés plutôt que restaurés. Cette technique doit néanmoins être utilisée consciemment : dans le fonctionnement normal, il faut considérer que l'OP détruit ou fait évoluer une partie de l'état de ses objets et que cet état doit être préparé de nouveau avant la prochaine trame.

L'Object Processor doit ainsi être compris comme un moteur matériel de parcours et de composition de lignes, et non comme un simple lecteur de sprites. À chaque ligne, il suit une Object List chaînée en DRAM, sélectionne les objets actifs, récupère leurs pixels par phrases et construit le line buffer. En contrepartie de cette automatisation, le programmeur doit respecter les types d'objets, leurs contraintes d'alignement, la portée limitée des liens et surtout le caractère modifiable des descripteurs, dont certains champs sont directement consommés par le matériel pendant l'affichage.

Objet Bitmap

L'objet Bitmap constitue l'un des types d'objets fondamentaux traités par l'Object Processor (OP) de la console Atari Jaguar. Il sert à décrire une image ou une portion d'image que l'OP doit transférer vers le line buffer pendant la génération de l'affichage. Un objet Bitmap est principalement décrit par deux phrases de 64 bits contenant son type, sa position, ses dimensions, son adresse en mémoire, son format de pixels et différents paramètres contrôlant la manière dont l'image doit être affichée.

La première phrase de 64 bits contient les informations générales permettant à l'Object Processor d'identifier l'objet, de savoir quand il doit être affiché et où trouver ses données. Les bits 0 à 2 contiennent TYPE, qui identifie le type de l'objet. Les bits 3 à 13 contiennent YPOS, c'est-à-dire sa position verticale. Les bits 14 à 23 contiennent HEIGHT, qui représente le nombre de lignes restant à traiter pour le Bitmap.

Les bits 24 à 42 de cette première phrase contiennent LINK. Ce champ indique à l'Object Processor où se trouve l'objet suivant dans l'Object List. L'OP peut ainsi progresser d'un descripteur au suivant sans que ceux-ci soient nécessairement considérés comme une simple structure linéaire implicite. Une valeur incorrecte dans LINK peut envoyer l'Object Processor vers une mauvaise région de mémoire ou perturber complètement le parcours de la liste.

Les bits 43 à 63 contiennent le champ DATA, qui indique l'adresse des données graphiques du Bitmap. Cette adresse est représentée sous la forme d'une adresse de phrase, une phrase correspondant à 64 bits, soit 8 octets. Le champ ne doit donc pas être interprété comme une adresse d'octet ordinaire stockée directement sur 21 bits. Cette représentation est adaptée au fonctionnement interne 64 bits de l'Object Processor et à ses accès aux données graphiques.

La deuxième phrase de 64 bits décrit plus précisément la disposition du Bitmap. Les bits 0 à 11 contiennent XPOS, la position horizontale de l'objet. Ce champ est signé, ce qui permet notamment de représenter une position négative lorsqu'une partie de l'image commence à gauche de la zone visible. Les bits 12 à 14 contiennent DEPTH, qui définit la profondeur des pixels.

Les bits 15 à 17 contiennent PITCH, un paramètre participant à la manière dont l'Object Processor parcourt les données du Bitmap. Les bits 18 à 27 contiennent DWIDTH, tandis que les bits 28 à 37 contiennent IWIDTH. Ces champs décrivent l'organisation de l'image en mémoire et sont exprimés relativement aux phrases de 64 bits, ce qui doit être pris en compte lors de la construction du descripteur.

Le champ IWIDTH représente la largeur de l'image utilisée par l'Object Processor et est exprimé en phrases. Une contrainte importante est qu'IWIDTH ne doit pas être égal à zéro. Même dans le cas d'une très petite image, le descripteur doit donc fournir une valeur valide correspondant à son organisation réelle en mémoire. Une valeur nulle ne doit pas être utilisée comme raccourci pour représenter une largeur minimale.

Le champ DWIDTH détermine quant à lui le pas de ligne en phrases. Il indique donc comment progresser dans les données pour atteindre la partie appropriée de l'image lors du traitement des lignes suivantes. IWIDTH et DWIDTH ont ainsi des fonctions liées mais distinctes : l'un décrit la largeur utilisée par le traitement de l'image, tandis que l'autre participe au déplacement entre les lignes dans la représentation mémoire du Bitmap.

Le champ DEPTH encode la profondeur des données graphiques. Selon sa valeur, l'Object Processor peut manipuler des images utilisant 1, 2, 4, 8, 16 ou 32/24 bits par pixel. Les petites profondeurs sont particulièrement adaptées aux images utilisant une palette, tandis que les formats de profondeur supérieure permettent de représenter directement davantage d'informations de couleur. La signification exacte des données dépend donc simultanément de DEPTH et des autres paramètres de l'objet.

La partie restante de la deuxième phrase contient plusieurs autres champs documentés par l'architecture de l'Object Processor. Ils comprennent notamment un index de palette, utilisé avec les formats indexés pour sélectionner la partie appropriée de la palette, ainsi que différents flags contrôlant le comportement du Bitmap. Parmi ceux-ci figurent les paramètres de réflexion, de RMW (Read-Modify-Write), de transparence, de release et de first pixel. Leur position et leur interprétation doivent respecter les champs définis par la documentation matérielle.

Les options de réflexion permettent de modifier le sens dans lequel certaines données de l'image sont parcourues, tandis que le mode RMW intervient lorsque l'Object Processor doit effectuer une opération de type Read-Modify-Write plutôt qu'une simple écriture. Le contrôle de transparence permet pour sa part de ne pas remplacer certains pixels déjà présents dans le line buffer. Le mécanisme release intervient dans la gestion de l'accès aux ressources mémoire, tandis que le champ associé au first pixel permet de tenir compte du point de départ effectif des pixels à l'intérieur de l'organisation en phrases.

La transparence est particulièrement importante avec les Bitmaps utilisant des pixels ou des indices de palette. La couleur ou l'index zéro est fréquemment utilisé comme valeur transparente lorsque le mode correspondant est activé. Les pixels ayant cette valeur peuvent alors être ignorés par l'Object Processor, laissant apparaître le contenu déjà présent dans le line buffer. Cette technique permet notamment de superposer des sprites ou d'autres éléments graphiques sans devoir entreposer explicitement un canal alpha pour chaque pixel.

L'adresse contenue dans DATA doit pointer vers une zone mémoire organisée conformément aux exigences de l'Object Processor. En particulier, les données du Bitmap doivent être paddées jusqu'à une phrase complète de 64 bits. Même si la dernière partie utile d'une ligne ou d'une image ne remplit pas entièrement cette phrase, l'espace mémoire nécessaire doit être prévu. Cette marge évite que l'OP lise au-delà d'une allocation trop courte lorsqu'il effectue ses accès par phrases.

La construction d'un objet Bitmap exige donc de coordonner correctement TYPE, YPOS, HEIGHT, LINK et DATA dans la première phrase, puis XPOS, DEPTH, PITCH, DWIDTH, IWIDTH, l'index de palette et les différents flags dans la seconde. Il faut également respecter l'unité en phrases utilisée par plusieurs champs, garantir un IWIDTH non nul et fournir des données suffisamment paddées. Une erreur dans l'un de ces paramètres peut provoquer une mauvaise position, un format de pixels incorrect, un mauvais pas entre les lignes ou des lectures mémoire indésirables par l'Object Processor.

Objet Bitmap redimensionné

L'Object Processor (OP) de la console Atari Jaguar possède un type d'objet permettant d'afficher un Bitmap redimensionné, souvent désigné comme un Scaled Bitmap Object. Son organisation reprend en grande partie celle d'un Bitmap ordinaire. Les deux premières phrases de 64 bits de son descripteur ressemblent donc à celles utilisées pour un objet Bitmap classique et fournissent les informations nécessaires pour localiser et afficher l'image. Le redimensionnement nécessite toutefois des paramètres supplémentaires, placés dans une troisième phrase.

Dans cette troisième phrase, les bits 0 à 7 contiennent HSCALE, qui contrôle le facteur d'échelle horizontal, tandis que les bits 8 à 15 contiennent VSCALE, utilisé pour le redimensionnement vertical. Les bits 16 à 23 contiennent REMAINDER, une valeur d'accumulation employée pendant le traitement vertical de l'image. Le reste de cette phrase doit être maintenu à zéro. Ces champs doivent être construits avec précision, car une valeur incorrecte peut produire une taille inattendue ou perturber le fonctionnement du redimensionnement.

Les facteurs HSCALE et VSCALE utilisent un format numérique fixe 3.5. Cela signifie que la valeur comporte 3 bits pour la partie entière et 5 bits pour la partie fractionnaire. Dans cette représentation, la valeur hexadécimale $20 correspond à 1,0. Un facteur de $20 signifie donc que l'image doit conserver sa dimension normale sur l'axe concerné. Les valeurs différentes de $20 provoquent une réduction ou un agrandissement selon la manière dont l'Object Processor accumule et applique le facteur d'échelle.

Le champ REMAINDER joue un rôle essentiel dans le redimensionnement vertical. Lors de l'initialisation normale d'un Scaled Bitmap, il commence généralement avec une valeur égale à VSCALE. À mesure que les lignes d'écran sont produites, l'Object Processor décrémente et met à jour cette valeur, puis décide quand il doit avancer vers une nouvelle ligne de l'image source en fonction de l'accumulation obtenue. Ce mécanisme permet de répéter certaines lignes lors d'un agrandissement ou, au contraire, d'en sauter lors d'une réduction.

Puisque l'Object Processor modifie REMAINDER pendant le traitement, cette valeur ne doit pas nécessairement être considérée comme intacte après l'affichage de l'objet. Lorsqu'un Scaled Bitmap doit être réutilisé à l'image suivante, le logiciel doit donc restaurer correctement REMAINDER, généralement à partir de VSCALE, avec les autres champs que l'OP a modifiés. Dans le cas contraire, le redimensionnement de l'image suivante pourrait commencer avec l'état d'accumulation laissé par la précédente.

Le mécanisme matériel possède également certaines limites. Des valeurs de VSCALE dépassant certaines plages, notamment des facteurs supérieurs à environ 7,0, ne fonctionnent pas correctement et doivent être évitées. Il ne faut donc pas considérer l'intégralité des valeurs théoriquement représentables par le champ comme nécessairement exploitable pour produire un affichage valide.

Le format RGB24 présente lui aussi des restrictions lorsqu'il est utilisé avec les Scaled Bitmaps. Le redimensionnement de données RGB sur 24 bits est limité et peut produire des déformations lorsque le facteur utilisé s'éloigne de 1:1. Une image RGB24 qui fonctionne correctement sans changement d'échelle ne doit donc pas être supposée compatible avec tous les facteurs de redimensionnement. Ces limitations matérielles doivent être prises en compte aussi bien lors de la programmation de la Jaguar réelle que lors de l'implémentation précise de son Object Processor dans un émulateur.

Le redimensionnement effectué par l'Object Processor reste par ailleurs relativement simple. Il s'apparente à une méthode de type nearest-neighbor, ou plus exactement à un mécanisme fondé sur la répétition et le saut de pixels ou de lignes. Pour agrandir une image, certains pixels ou certaines lignes sont répétés ; pour la réduire, certains sont ignorés. L'OP ne calcule pas de moyenne entre plusieurs pixels voisins et n'effectue donc aucune filtration bilinéaire destinée à adoucir automatiquement l'image redimensionnée.

Enfin, le Scaled Bitmap ne constitue pas un système général de transformation géométrique. Il permet essentiellement de modifier l'échelle horizontale et verticale d'une image selon les capacités de l'Object Processor. Pour effectuer une rotation, une transformation en perspective ou du texture mapping, il faut faire intervenir le GPU et le Blitter. Ceux-ci peuvent calculer et préparer une nouvelle image ou construire les spans nécessaires au rendu, puis laisser l'Object Processor afficher le résultat obtenu. Le Scaled Bitmap est donc un mécanisme matériel rapide pour le redimensionnement, mais il ne remplace pas les opérations graphiques plus générales nécessaires à un véritable rendu 2D transformé ou 3D.

Objets GPU, branchement et STOP

L'Object Processor (OP) de la console Atari Jaguar ne traite pas uniquement des objets Bitmap destinés à afficher directement des pixels. Son Object List peut également contenir des objets de contrôle qui modifient le déroulement du traitement. Parmi ceux-ci figurent notamment le GPU Object de type 2, le Branch Object de type 3 et le Stop Object de type 4. Ces objets permettent respectivement de faire intervenir le GPU pendant le parcours de la liste, d'effectuer des branchements conditionnels et de terminer proprement le traitement de l'Object List.

Un GPU Object de type 2 provoque une interruption du GPU lorsque l'Object Processor le rencontre. Il permet ainsi d'insérer une intervention programmable au milieu du traitement matériel de l'Object List. Les informations contenues dans le champ DATA de l'objet sont rendues accessibles au GPU à travers les registres OB0 à OB3. Le programme exécuté par le GPU peut donc examiner ces informations et les utiliser pour déterminer le traitement à effectuer.

Une fois interrompu par cet objet, le GPU peut réaliser différentes opérations avant que l'Object Processor poursuive son travail. Il peut notamment effectuer des calculs, modifier certains éléments de l'Object List ou intervenir sur le line buffer utilisé pendant la construction de l'image. Cette possibilité permet d'introduire des traitements programmables à des endroits précis du parcours de la liste, au lieu de limiter l'affichage à une séquence entièrement déterminée à l'avance.

Après avoir terminé le traitement demandé, le GPU doit permettre à l'Object Processor de reprendre son exécution. Pour cela, il effectue l'écriture prévue dans OBF, ce qui sert à relancer l'OP après l'interruption provoquée par le GPU Object. La synchronisation entre les deux processeurs est donc essentielle : l'OP s'arrête sur l'objet de type 2, le GPU effectue son traitement, puis signale explicitement que le parcours de la liste peut continuer.

Le Branch Object de type 3 joue un rôle différent. Il constitue le mécanisme de branchement conditionnel de l'Object Processor. Lorsqu'il rencontre cet objet, l'OP évalue une condition pouvant notamment comparer YPOS avec VC, le compteur vertical utilisé pour connaître la position courante du balayage vidéo. Selon le mode sélectionné, le branchement peut également dépendre d'un flag de l'Object Processor ou d'une condition liée à la demi-ligne.

Lorsque la condition définie par le Branch Object est vraie, l'Object Processor ne poursuit pas simplement avec l'objet suivant en mémoire : il utilise le champ LINK afin de continuer le parcours de l'Object List à l'adresse indiquée. Lorsque la condition n'est pas satisfaite, le traitement continue selon le chemin normal prévu par la liste. Les Branch Objects permettent donc de construire des structures conditionnelles dans l'Object List sans intervention permanente du 68000 ou du GPU.

Ces branchements sont particulièrement importants aux limites de la zone vidéo active. Une Object List robuste devrait commencer par des Branch Objects permettant d'exclure les lignes situées en dehors de l'affichage actif. L'objectif est d'empêcher l'Object Processor de parcourir inutilement les objets graphiques pendant les périodes où aucune ligne visible ne doit être produite.

Cette précaution est nécessaire parce que l'Object Processor ne se contente pas toujours de lire passivement les objets. Pendant son fonctionnement, il peut consommer ou modifier certains champs de leurs descripteurs. Si la liste est parcourue pendant une période de blanking, alors qu'elle ne devrait pas encore traiter les objets destinés à l'image visible, certaines informations peuvent être modifiées prématurément. Les branches placées au début de la liste servent donc à détourner le parcours pendant les lignes situées hors de la région d'affichage actif.

Le Stop Object de type 4 constitue pour sa part la terminaison normale de l'Object List. Lorsqu'il rencontre cet objet, l'Object Processor comprend qu'il a atteint la fin du parcours prévu et cesse de rechercher d'autres objets. Le Stop Object peut également être configuré pour générer une interruption à destination du Motorola 68000, ce qui permet au programme principal d'être averti que l'OP a atteint ce point particulier de la liste.

Le champ DATA associé au Stop Object peut servir de marqueur. Le programme peut ainsi placer une valeur déterminée dans l'objet afin d'identifier la fin atteinte ou d'associer des informations au STOP rencontré. Cette possibilité est utile pour le diagnostic, la synchronisation ou l'identification d'un chemin particulier lorsqu'une Object List comporte plusieurs branchements conduisant vers des points de terminaison.

Il est essentiel qu'une Object List correctement construite finisse toujours par atteindre un objet STOP. Les branchements doivent donc être organisés de manière à garantir qu'il existe un chemin de terminaison valide. Une erreur de LINK ou une combinaison incorrecte de Branch Objects peut créer une boucle, dans laquelle l'Object Processor parcourt continuellement les mêmes objets sans jamais rencontrer le STOP.

Une telle boucle est beaucoup plus grave qu'une simple boucle logicielle inutile. L'Object Processor est un composant matériel qui utilise directement les ressources mémoire et vidéo de la Jaguar. S'il reste enfermé dans une Object List cyclique, il peut monopoliser ou fortement perturber le bus et le système vidéo, compromettant le fonctionnement de l'affichage et des autres unités qui doivent accéder à la mémoire. L'absence d'un chemin fiable vers STOP doit donc être considérée comme une erreur critique dans la construction de la liste.

Enfin, certains outils de développement de la Jaguar, notamment RMAC, proposent des pseudo-objets tels que nop ou jump afin de rendre la description d'une Object List plus pratique et plus lisible. Ces constructions ne correspondent toutefois pas à de nouveaux types d'objets reconnus directement par le silicium de l'Object Processor. Lors de l'assemblage, elles sont traduites en Branch Objects matériels configurés de manière à produire le comportement désiré. Il faut donc distinguer les facilités syntaxiques offertes par l'assembleur des véritables types d'objets compris par le matériel de la Jaguar.

Construction et restauration d'une Object List

Sur la console Atari Jaguar, l'Object List est la structure de données parcourue par l'Object Processor (OP) afin de déterminer les objets qui doivent être traités pour produire l'affichage. Sa construction doit respecter plusieurs règles matérielles précises. Les différents headers, ou en-têtes d'objets, doivent être correctement alignés en mémoire, et la liste doit être placée en DRAM. L'Object Processor lit directement ces structures pendant la génération de l'image ; une mauvaise disposition ou un mauvais alignement peut donc conduire à une interprétation incorrecte des objets.

Une difficulté supplémentaire vient de la manière dont le Motorola 68000 et les circuits spécialisés de la Jaguar voient certaines données de 64 bits. Lorsqu'une phrase constituant un en-tête d'objet est préparée depuis le 68000, il faut tenir compte du word swapping, c'est-à-dire de l'ordre particulier des mots à l'intérieur de cette phrase. Il est préférable d'utiliser les macros prévues à cet effet plutôt que de construire manuellement les valeurs en supposant qu'elles seront vues dans le même ordre par tous les composants. Ces macros permettent de produire en mémoire une représentation conforme à celle attendue par l'Object Processor.

Une Object List correctement construite doit également prévoir les éléments nécessaires au clipping. La structure recommandée comporte notamment deux objets de type Branch utilisés pour le clip, afin d'orienter le parcours de la liste selon les conditions prévues. Ces branches permettent à l'Object Processor de sauter certaines parties de la liste lorsque les conditions de position ou d'affichage correspondantes sont rencontrées. Elles font donc partie de l'organisation de la liste et ne doivent pas être considérées comme de simples objets graphiques.

La fin de l'Object List doit être explicitement signalée par un objet STOP. Celui-ci indique à l'Object Processor qu'il ne doit plus poursuivre la lecture des objets. Sans terminaison correcte, l'OP pourrait continuer à interpréter comme des en-têtes d'objets des données situées après la liste. La construction générale doit donc respecter une chaîne cohérente d'objets et de liens, commencer sur des adresses convenablement alignées, intégrer les branches nécessaires et se terminer par un STOP.

Une fois la liste préparée, son adresse doit être fournie à l'Object Processor par l'intermédiaire de OLP (Object List Pointer). L'initialisation de ce pointeur doit être réalisée une seule fois et de manière atomique, de préférence avec l'aide du GPU. Une fois que l'OP connaît l'adresse de la liste, il n'est généralement pas nécessaire de réécrire constamment OLP pour animer ou déplacer les objets. Le contenu de la liste existante peut être mis à jour directement en mémoire.

Cette distinction est importante parce que l'Object Processor modifie lui-même certaines informations des objets pendant leur traitement. À chaque VBlank, c'est-à-dire pendant la période de retour vertical séparant deux images, le programme doit donc restaurer les champs que l'OP a consommés ou modifiés et qui doivent retrouver leur valeur initiale pour l'image suivante. Pour les objets Bitmap, il faut restaurer au minimum les champs DATA et HEIGHT.

Dans le cas des objets Scaled Bitmap, il faut également restaurer le REMAINDER utilisé pendant le processus de mise à l'échelle. Cette valeur participe à l'accumulation nécessaire au redimensionnement et peut évoluer pendant le traitement de l'objet. Si elle n'est pas remise dans l'état approprié avant l'image suivante, le comportement du scaling peut progressivement devenir incorrect ou commencer dans un état différent de celui attendu.

Après la restauration de ces informations, le programme peut mettre à jour les paramètres réellement variables de la scène. Il peut notamment modifier XPOS et YPOS afin de déplacer les objets à l'écran, ainsi que les liens lorsqu'une modification de l'organisation ou du parcours de l'Object List le nécessite. Les mises à jour doivent donc cibler les champs qui ont effectivement changé plutôt que provoquer systématiquement une reconstruction complète de la structure.

Si, par exemple, un objet doit simplement se déplacer et que seules ses coordonnées changent, il est inutile de reconstruire toute l'Object List à chaque image. Il suffit de restaurer les champs que l'Object Processor a modifiés, puis de changer les deux coordonnées nécessaires. Cette méthode réduit le travail du CPU ou du GPU, limite les écritures en DRAM et évite de reconstruire des en-têtes et des liens qui n'ont subi aucune modification logique.

Une précaution particulièrement importante concerne l'écriture de OLP depuis le Motorola 68000. Atari recommande de ne pas modifier directement ce pointeur depuis le 68000, car une valeur de 32 bits peut nécessiter deux accès correspondant aux deux mots de 16 bits. Entre ces deux écritures, l'Object Processor pourrait reprendre ou préempter l'accès et observer momentanément un pointeur composé d'une moitié ancienne et d'une moitié nouvelle. Il pourrait alors commencer à parcourir une adresse incorrecte.

Le GPU permet d'éviter ce problème parce qu'il peut effectuer une écriture 32 bits atomique sur son chemin interne pour cette opération. L'Object Processor ne peut donc pas observer un OLP partiellement mis à jour entre deux moitiés de la valeur. Une stratégie robuste consiste ainsi à construire correctement l'Object List en DRAM, à demander au GPU d'installer atomiquement son adresse dans OLP, puis à conserver ce pointeur aussi stable que possible. À chaque VBlank, le programme restaure ensuite les champs consommés par l'OP et ne modifie que les coordonnées, liens ou autres paramètres qui ont réellement changé.

GPU : Architecture

Le GPU (Graphics Processing Unit) de la console Atari Jaguar est un processeur RISC 32 bits intégré à la puce TOM. Contrairement au Motorola 68000 utilisé comme processeur principal de la console, le GPU a été conçu spécialement pour effectuer rapidement de nombreux calculs nécessaires aux traitements graphiques et multimédias. Son architecture est pipeline, ce qui signifie que plusieurs étapes appartenant à différentes instructions peuvent être traitées simultanément. Cette organisation augmente fortement le débit d'exécution, mais impose également de tenir compte des latences et des dépendances entre certaines instructions.

Le GPU dispose au total de 64 registres de 32 bits, organisés sous la forme de deux banques de 32 registres. Une banque est normalement active tandis que l'autre peut servir de banque alternative, notamment dans certaines situations liées aux interruptions et aux changements de contexte. Cette grande quantité de registres permet de conserver directement dans le processeur de nombreuses coordonnées, adresses, compteurs et valeurs intermédiaires, ce qui limite les accès à la mémoire et améliore les performances des routines intensives en calcul.

Son unité d'exécution comprend notamment une ALU (Arithmetic Logic Unit) destinée aux opérations arithmétiques et logiques courantes. Le GPU possède également des mécanismes matériels pour les multiplications et les divisions, opérations particulièrement utiles pour les calculs graphiques. À cela s'ajoutent la logique nécessaire au contrôle des branchements ainsi qu'une interface mémoire permettant au processeur d'accéder aussi bien à sa RAM locale qu'aux autres zones de mémoire accessibles dans l'architecture de la Jaguar.

Bien que le GPU manipule principalement des données et des registres de 32 bits, son code machine utilise des instructions de 16 bits. Il faut donc distinguer la largeur des données de la taille de l'encodage des instructions : qualifier le GPU de processeur 32 bits ne signifie pas que chacune de ses instructions occupe 32 bits en mémoire. Cet encodage relativement compact est particulièrement avantageux compte tenu de la faible quantité de mémoire locale disponible pour stocker le programme.

Le GPU fonctionne avec l'horloge système d'environ 26,59 MHz. Sa fréquence peut sembler faible selon des critères modernes, mais son architecture RISC, ses nombreux registres et ses unités spécialisées lui permettent d'effectuer efficacement des calculs répétitifs. Ses performances dépendent cependant fortement de la manière dont le programme organise les instructions et les accès mémoire. Un programme conservant ses données critiques dans les registres et sa boucle principale dans la mémoire locale peut être beaucoup plus efficace qu'un programme effectuant continuellement des accès à la DRAM externe.

Le GPU est particulièrement adapté aux transformations graphiques et aux calculs nécessaires avant ou pendant le rendu. Il peut, par exemple, effectuer des transformations de coordonnées servant à préparer des objets ou des polygones pour leur affichage. Il convient également très bien à certaines tâches de décompression, ce qui permet de stocker des ressources sous une forme compacte puis de les reconstruire au moment où elles sont nécessaires.

Une autre utilisation importante du GPU concerne la construction des spans. Dans un moteur graphique, notamment lors du dessin d'un triangle, le GPU peut calculer les limites gauche et droite du polygone pour chaque ligne de l'écran et déterminer ainsi les portions horizontales à dessiner. Une fois ces spans calculés, il peut configurer et lancer le Blitter, qui effectue efficacement le traitement des pixels correspondants. Le GPU et le Blitter travaillent donc fréquemment ensemble plutôt que comme deux unités graphiques complètement indépendantes.

Le GPU convient également aux calculs nécessaires à l'animation et au pilotage des autres circuits graphiques de TOM. Il peut préparer des coordonnées, modifier des paramètres d'objets ou construire des données nécessaires à une animation, puis contrôler le Blitter et l'Object Processor (OP). Dans cette organisation, le GPU réalise une partie importante des calculs et de l'orchestration, tandis que les unités spécialisées effectuent les opérations pour lesquelles elles ont été conçues.

Pour obtenir de bonnes performances, le GPU dispose d'une RAM locale de 4 Kio. Cette mémoire est très petite, mais elle est beaucoup plus favorable à l'exécution rapide du code critique que la DRAM principale. Elle doit donc être utilisée avec discernement. Les boucles les plus importantes, les petits noyaux de calcul et les données fréquemment consultées sont de bons candidats pour cette mémoire locale.

Le GPU peut également exécuter du code situé en DRAM, mais cette possibilité est nettement moins performante. Les accès à la mémoire principale passent par les ressources partagées de la Jaguar et peuvent être soumis à la contention du bus et de la mémoire avec le Motorola 68000, l'Object Processor, le Blitter et d'autres unités. Le GPU peut alors perdre des cycles en attendant que les données ou les instructions demandées deviennent accessibles. Une routine théoriquement rapide peut ainsi être fortement ralentie si elle dépend trop de la DRAM.

Une stratégie efficace consiste donc à charger dans les 4 Kio de RAM locale le noyau du programme et les tables les plus critiques, puis à conserver en mémoire principale ce qui est trop volumineux ou moins fréquemment utilisé. La programmation performante du GPU de la Jaguar repose ainsi autant sur l'organisation de la mémoire que sur les instructions elles-mêmes : il faut exploiter les registres et la RAM locale pour les traitements intensifs tout en réduisant autant que possible les accès à la DRAM partagée.

GPU : Registres et mémoire locale

Le GPU (Graphics Processing Unit) de la console Atari Jaguar est l'un des processeurs RISC intégrés à la puce TOM. Il possède ses propres registres de contrôle ainsi qu'une petite mémoire locale très rapide destinée principalement à l'exécution de son code et au stockage temporaire de données. Pour programmer correctement le GPU depuis le Motorola 68000, il est essentiel de distinguer les différentes zones de son espace d'adressage et de respecter une séquence précise lors du chargement et du démarrage d'un programme.

La région comprise entre $F02000 et $F021FF contient les registres et les mécanismes de contrôle permettant notamment au reste de la Jaguar d'accéder au GPU. Les registres de contrôle proprement dits se trouvent autour de $F02100, chacun étant accessible à un offset déterminé. Parmi les principaux registres figurent FLAGS, MTX_ADDR, MTX_CTRL, DATA_ORG, PC, CTRL, HIDATA et REMAIN. Ils permettent de contrôler l'état du processeur, son compteur ordinal, ses interruptions et certaines unités ou fonctions particulières.

Le registre PC (Program Counter) contient l'adresse de l'instruction que le GPU doit exécuter. Il joue donc un rôle essentiel lors du démarrage d'un programme : après avoir chargé le code dans la mémoire locale, le 68000 peut positionner PC sur l'adresse du point d'entrée désiré. Les registres MTX_ADDR et MTX_CTRL sont associés au contrôle de fonctions internes du GPU, tandis que DATA_ORG intervient dans l'organisation des données. HIDATA et REMAIN sont également exposés parmi les registres du processeur et servent aux opérations auxquelles leurs unités internes respectives les associent. Leur signification exacte doit être respectée selon les offsets et les règles définis par la documentation matérielle.

Le GPU dispose de 4 Kio de RAM locale, située dans la région $F03000-$F03FFF. Cette mémoire est directement associée au GPU et constitue l'emplacement privilégié pour son programme ainsi que pour les données auxquelles il doit accéder rapidement. Sa faible capacité impose cependant une gestion attentive : code, tables, variables temporaires et éventuels gestionnaires d'interruptions doivent partager cet espace limité. L'organisation de cette RAM locale est donc un élément important de l'optimisation des programmes GPU.

Une autre fenêtre, située entre $F0B000 et $F0BFFF, fournit une vue 32 bits de la RAM locale du GPU. Il s'agit d'un accès à la même mémoire selon une organisation adaptée aux transferts correspondants, et non d'une seconde RAM indépendante de 4 Kio. Cette distinction est importante lorsqu'un programme exécuté par le 68000 charge du code ou des données destinés au GPU : les différentes adresses représentent des voies d'accès au entreposage local du processeur.

Le GPU possède également deux banques de 32 registres. À un instant donné, l'une constitue la banque active utilisée par les instructions ordinaires, tandis que l'autre constitue une banque alternative. Cette organisation permet notamment de changer rapidement de contexte dans certaines situations, en particulier lors du traitement des interruptions. Elle réduit la quantité de données qu'il faut immédiatement déplacer en mémoire, même si certains états ou registres partagés doivent toujours être sauvegardés explicitement lorsque cela est nécessaire.

Le registre FLAGS rassemble plusieurs informations fondamentales sur l'état du GPU. Il contient notamment les drapeaux arithmétiques Z, C et N : Z indique typiquement un résultat nul (Zero), C représente la retenue (Carry) et N indique un résultat négatif (Negative). Ces drapeaux peuvent être utilisés par les instructions conditionnelles et les branchements pour déterminer la suite de l'exécution.

FLAGS intervient également dans la gestion des interruptions. Certains de ses bits servent à masquer des sources d'interruption, tandis que d'autres permettent leur acquittement ou leur effacement selon le mécanisme prévu par le GPU. Le registre participe en outre à la sélection de la banque de registres active. Modifier FLAGS ne revient donc pas simplement à modifier quelques indicateurs arithmétiques : une écriture incorrecte peut également changer l'état des interruptions ou la banque de registres utilisée par le programme.

Le registre CTRL assure pour sa part plusieurs fonctions générales de contrôle du GPU. Il contient notamment le bit RUN, qui détermine si le processeur est arrêté ou autorisé à exécuter son programme. D'autres bits participent au mécanisme d'interruption provenant de l'hôte, ainsi qu'à la génération d'une interruption du GPU vers le CPU. CTRL contient également des paramètres associés à l'endianness et au comportement des accès sur le bus, ce qui est particulièrement important lorsque le GPU échange des données avec le Motorola 68000 ou d'autres unités de la Jaguar.

Le chargement d'un programme GPU par le 68000 doit respecter une séquence précise. Avant de modifier le code présent dans la RAM locale, le processeur principal doit d'abord arrêter le GPU. Cette précaution empêche celui-ci d'exécuter simultanément des instructions dans une zone que le 68000 est justement en train de remplacer. Sans cet arrêt préalable, le GPU pourrait lire une instruction partiellement modifiée ou continuer son exécution dans une région devenue incohérente.

Une fois le GPU arrêté, le 68000 peut charger le programme dans sa RAM locale, en effectuant les écritures de code sous forme de longs, c'est-à-dire de valeurs de 32 bits, conformément à la méthode d'accès prévue. Après le chargement, il faut positionner PC sur le point d'entrée du programme. Les flags et états nécessaires doivent ensuite être effacés ou initialisés correctement afin que le nouveau programme ne démarre pas avec des conditions résiduelles provenant d'une exécution précédente.

Lorsque la mémoire, PC et les registres nécessaires sont prêts, le 68000 peut finalement positionner RUN dans CTRL afin de démarrer le GPU. Le processeur RISC commence alors à exécuter le programme à l'adresse indiquée par son compteur ordinal. Cette procédure - arrêter, charger, initialiser, fixer PC, puis démarrer - constitue la méthode sûre pour remplacer un programme GPU.

La même précaution s'applique lorsqu'un nouveau programme doit être chargé ultérieurement. Il ne suffit pas de demander l'arrêt du GPU et de commencer immédiatement à écraser sa RAM : le logiciel doit vérifier que le GPU est effectivement arrêté avant de recharger son code. Cette synchronisation évite qu'une ancienne instruction soit encore en cours d'exécution pendant la modification de la mémoire locale et garantit que le nouveau programme démarre avec un état cohérent.

Ensemble d'instructions RISC Jaguar

Format général 16 bits : opcode 6 bits, source 5, destination 5.

Catégorie Instructions
Arithmétique ADD, ADDC, ADDQ, ADDQT, SUB, SUBC, SUBQ, SUBQT, NEG.
Logique/bit AND, OR, XOR, NOT, BTST, BSET, BCLR.
Multiplication MULT, IMULT, IMULTN, IMACN, RESMAC.
Division/valeur DIV, ABS.
Décalage/rotation SH, SHLQ, SHRQ, SHA, SHARQ, ROR, RORQ.
Comparaison CMP, CMPQ.
Transfert MOVE, MOVEQ, MOVEI, MOVETA, MOVEFA, MOVE PC.
Mémoire LOADB, LOADW, LOAD, LOADP, STOREB, STOREW, STORE, STOREP.
Contrôle JUMP, JR et NOP.
GPU SAT8, SAT16, SAT24, PACK, UNPACK, MMULT, MTOI, NORMI.
DSP ADDQMOD, SUBQMOD, SAT16S/SAT32S, MIRROR et opérations MAC associées.

Disponibilité exacte différé GPU/DSP. LOADP/STOREP traitent phrase 64 bits via deux registres/chemin spécial. MOVEI occupe des mots supplémentaires. Les quick immédiates ont encodages particuliers (zéro peut signifier 32).

Pipeline, hazards et banques de registres

Les processeurs RISC de la console Atari Jaguar, en particulier le GPU de TOM et le DSP de JERRY, utilisent une architecture en pipeline afin d'exécuter rapidement leurs instructions. Cependant, leur matériel ne fournit pas tous les mécanismes d'interlock que l'on pourrait attendre d'un processeur plus moderne. Un interlock sert normalement à détecter automatiquement qu'une instruction dépend du résultat d'une instruction précédente et à retarder son exécution jusqu'à ce que cette valeur soit réellement disponible. Sur les RISC de la Jaguar, certaines de ces dépendances doivent donc être gérées explicitement par le programmeur.

Cette particularité provoque ce que l'on appelle des hazards de pipeline, ou conflits de dépendance. Une instruction peut avoir été exécutée sans que son résultat soit encore disponible à l'endroit où l'instruction suivante cherche à le lire. Si cette seconde instruction arrive trop rapidement, elle peut obtenir l'ancienne valeur du registre plutôt que le résultat qui vient d'être calculé. Le programme peut alors produire un résultat incorrect même si, à première vue, la succession des instructions semble parfaitement logique.

Ce problème est particulièrement important après certaines opérations ayant une latence de plusieurs cycles, notamment un LOAD, une division, une multiplication ou certaines opérations impliquant un write-back, c'est-à-dire l'étape pendant laquelle un résultat est finalement réécrit dans un registre. Par exemple, si une instruction charge une valeur depuis la mémoire et que l'instruction immédiatement suivante utilise le registre de destination, la donnée peut ne pas encore être disponible. Le même principe s'applique lorsque le résultat d'une multiplication ou d'une division est consommé avant que l'unité correspondante ait terminé son travail.

Pour éviter ces situations, le programmeur doit respecter les latences indiquées dans les tableaux du manuel matériel de la Jaguar. Lorsqu'un certain nombre de cycles doit séparer la production d'une valeur de son utilisation, il est possible d'insérer une ou plusieurs instructions NOP (No Operation). Une meilleure optimisation consiste, lorsque cela est possible, à placer dans cet intervalle du travail indépendant, c'est-à-dire des instructions qui ne dépendent pas du résultat encore indisponible. Les cycles nécessaires sont alors utilisés pour effectuer un travail utile au lieu d'être simplement perdus dans des NOP.

Les branchements demandent eux aussi une attention particulière en raison du fonctionnement du pipeline. Lorsqu'une instruction de branchement modifie le flot d'exécution, les instructions déjà engagées dans le pipeline ne disparaissent pas nécessairement immédiatement. Il existe donc des contraintes de délai de branchement et de pipeline dont le programmeur doit tenir compte. L'instruction située juste après une branche occupe une position particulièrement sensible, souvent assimilée à un slot de délai dans la programmation de ce type de RISC.

Toutes les instructions ne peuvent cependant pas être placées sans précaution dans ce slot suivant une branche. Certaines combinaisons sont interdites ou produisent un comportement incorrect en raison des caractéristiques du pipeline et des limitations du matériel. Il ne suffit donc pas de remplir systématiquement le délai avec n'importe quelle instruction pour gagner un cycle. Le programmeur doit vérifier les règles données dans la documentation et choisir une instruction compatible, ou employer un NOP lorsqu'aucune instruction utile ne peut y être placée en toute sécurité.

Le GPU et le DSP disposent également de banques de registres, dont l'utilisation devient particulièrement importante lors du traitement des interruptions. Un changement de banque permet au processeur de disposer rapidement d'un autre ensemble de registres sans devoir sauvegarder immédiatement la totalité du contexte courant. Cette technique peut accélérer l'entrée dans un gestionnaire d'interruption, mais elle ne signifie pas que tous les registres deviennent automatiquement indépendants.

Certains registres ou états restent en effet partagés entre les contextes ou les banques. Lorsqu'une interruption provoque un changement de banque de registres, le gestionnaire doit donc préserver explicitement les valeurs partagées qu'il risque de modifier. À la fin du traitement, ces valeurs doivent être restaurées et le retour d'interruption doit être effectué dans l'ordre prévu par l'architecture. Une mauvaise séquence de sauvegarde, de restauration ou de changement de banque peut corrompre le contexte du programme interrompu et provoquer des erreurs particulièrement difficiles à reproduire.

À ces contraintes architecturales s'ajoutent plusieurs bogues et anomalies connus du silicium des processeurs GPU et DSP de la Jaguar. Certaines révisions du matériel présentent des comportements problématiques concernant notamment le scoreboarding, c'est-à-dire le suivi interne des dépendances entre instructions, ainsi que la gestion des flags, certaines opérations STORE, les branchements et le traitement des interruptions. Le comportement réel du processeur peut donc, dans certains cas particuliers, différer de celui que laisserait prévoir une interprétation idéale de son architecture.

La programmation fiable des RISC de la Jaguar exige par conséquent de tenir compte simultanément des latences du pipeline, des dépendances entre instructions, des règles concernant les branchements, de la gestion des banques de registres et des errata matériels du GPU et du DSP. Pour un programme destiné au matériel réel - ou pour un émulateur cherchant à reproduire fidèlement celui-ci - ces contraintes ne sont pas de simples optimisations : elles peuvent déterminer si un programme fonctionne correctement. Les tableaux de latence et les errata du manuel doivent donc être considérés comme une partie essentielle de la spécification des processeurs RISC de la Jaguar.

Blitter : Architecture

Le Blitter de la console Atari Jaguar est un moteur matériel 64 bits intégré à TOM, l'une des principales puces personnalisées de la console. Son rôle est d'accélérer de nombreuses opérations graphiques qui seraient beaucoup plus coûteuses si elles étaient entièrement réalisées par le Motorola 68000 ou le GPU. Il peut notamment effectuer des copies de blocs graphiques, des remplissages de zones, des opérations logiques, des traitements de transparence, des comparaisons, des opérations utilisant un Z-buffer, du shading ainsi que certaines opérations d'addition. Le Blitter constitue ainsi un moteur graphique polyvalent plutôt qu'un simple circuit destiné à copier des données d'une zone mémoire vers une autre.

Son architecture repose notamment sur deux générateurs d'adresses, appelés A1 et A2. Ceux-ci permettent de décrire les surfaces mémoire utilisées pendant une opération du Blitter. Une surface peut représenter, selon le traitement effectué, une image source, une texture, une zone de destination, un tampon d'affichage ou encore des données associées à la profondeur. Grâce aux deux générateurs, le Blitter peut parcourir simultanément deux organisations de données différentes et calculer les adresses nécessaires pendant le transfert ou le traitement.

Chaque générateur d'adresses possède plusieurs paramètres décrivant la manière dont sa surface est organisée. Une adresse de base indique où commencent les données en mémoire, tandis que différents flags précisent leur format et la façon dont elles doivent être interprétées. Le Blitter peut également tenir compte d'une zone de clipping, afin de limiter certaines opérations à une région déterminée. Les paramètres définissent aussi si les données sont manipulées sous forme de pixels individuels ou de phrases de 64 bits, cette dernière organisation permettant d'exploiter plus efficacement la largeur interne du moteur.

Les générateurs A1 et A2 tiennent également compte du pitch et de la width de la surface. La largeur décrit l'organisation horizontale des données, tandis que le pitch intervient dans la manière dont les adresses progressent en mémoire lorsque le Blitter parcourt la surface. Ces informations sont essentielles lorsque la disposition physique des données ne correspond pas simplement à une suite linéaire de pixels. Le Blitter peut ainsi calculer automatiquement les adresses suivantes en fonction de la structure de l'image et du déplacement demandé.

Une caractéristique particulièrement importante de cette architecture est la possibilité d'utiliser des incréments fractionnaires. Les coordonnées et valeurs manipulées ne sont donc pas nécessairement limitées à des déplacements correspondant exactement à un pixel entier à chaque étape. Une partie fractionnaire peut être accumulée pendant le parcours, ce qui permet d'effectuer progressivement des interpolations. Ce mécanisme est particulièrement utile pour le mappage de textures, le Gouraud shading et l'interpolation des valeurs Z utilisées pour la profondeur.

Malgré ses nombreuses fonctions graphiques, le Blitter ne doit toutefois pas être considéré comme un processeur 3D capable de recevoir directement la description complète d'un triangle et de le rasteriser automatiquement. Il ne possède pas, à lui seul, un pipeline géométrique complet chargé de déterminer les sommets, les arêtes et tous les pixels intérieurs d'un triangle. Une partie importante du travail nécessaire au rendu 3D doit donc être effectuée par un autre processeur de la Jaguar.

Dans une utilisation typique, c'est le GPU qui effectue les calculs nécessaires pour déterminer les bords du polygone et les spans, c'est-à-dire les portions horizontales de pixels comprises entre les limites gauche et droite du polygone pour chaque ligne de l'écran. Une fois les coordonnées d'un span déterminées, le GPU configure les registres du Blitter et lui demande de tracer ou de traiter cette ligne. Le processus est ensuite répété pour les différentes lignes composant le triangle ou le polygone.

Cette coopération entre le GPU et le Blitter constitue donc un élément fondamental de l'architecture graphique de la Jaguar. Le GPU se charge principalement des calculs permettant de déterminer où les pixels doivent être produits, tandis que le Blitter réalise efficacement une grande partie du travail nécessaire pour déterminer et écrire leurs données graphiques. Pendant le traitement de chaque span, ses incréments fractionnaires permettent notamment de faire évoluer les coordonnées de texture, les valeurs utilisées pour le Gouraud shading et la profondeur Z. Cette séparation des tâches permet d'exploiter les capacités spécialisées des différents circuits de TOM pour accélérer le rendu graphique.

Blitter : Registres et commandes

Le Blitter de l'Atari Jaguar est contrôlé par un ensemble de registres matériels situés dans la région d'adresses $F02200-$F022FF. Ces registres définissent les adresses mémoire utilisées, le format des pixels, les déplacements à effectuer dans les images, le nombre d'éléments à traiter et les opérations graphiques à exécuter. Avant de lancer une opération, le programme doit donc préparer les différents registres nécessaires, puis transmettre au Blitter une commande décrivant précisément le traitement désiré.

Une première série de registres est associée au générateur d'adresses A1. Elle comprend A1_BASE, A1_FLAGS, A1_CLIP, A1_PIXEL, A1_STEP, A1_FSTEP, A1_FPIXEL, A1_INC et A1_FINC. A1_BASE fournit l'adresse de base de la surface manipulée, tandis que A1_FLAGS décrit notamment son organisation et son format. A1_CLIP intervient dans la définition des limites utilisées pour le clipping. Les registres A1_PIXEL et A1_FPIXEL participent au positionnement courant dans l'image, alors que A1_STEP, A1_FSTEP, A1_INC et A1_FINC déterminent les déplacements et incréments appliqués pendant l'opération, y compris les composantes fractionnaires lorsque celles-ci sont utilisées.

Le Blitter possède un deuxième générateur d'adresses, A2, disposant de registres équivalents à ceux nécessaires pour décrire et parcourir une seconde surface. Les deux ensembles permettent au Blitter de travailler avec des zones mémoire distinctes, par exemple lorsqu'une image doit être copiée d'un tampon vers un autre. Selon l'opération choisie, A1 et A2 peuvent ainsi représenter différentes surfaces ou différents parcours mémoire. La distinction entre ces deux générateurs est importante puisque la commande du Blitter détermine ensuite comment les données correspondantes sont utilisées.

À ces registres d'adressage s'ajoutent les registres directement liés à l'exécution des opérations. B_COUNT indique la quantité de données à traiter, tandis que B_CMD définit l'opération à réaliser. Le Blitter dispose également de registres de données comme B_SRCD pour les données sources, B_DSTD pour les données de destination, B_SRCZ et B_DSTZ pour les valeurs de profondeur Z, ainsi que B_PATD pour les données de motif (pattern). Des registres comme B_IINC et B_ZINC fournissent respectivement des incréments utilisés pour certaines opérations d'intensité et de profondeur. B_STOP intervient dans le contrôle ou l'arrêt du Blitter. Cet ensemble est complété par différents registres de données et de masques nécessaires aux opérations internes, notamment lorsque seule une partie d'une phrase doit être modifiée.

Le registre B_COUNT décrit les dimensions de l'opération sous la forme d'un nombre de lignes et d'un nombre de pixels par ligne. Une opération rectangulaire peut ainsi être décrite en indiquant combien de pixels doivent être traités horizontalement et combien de fois cette séquence doit être répétée verticalement. Les générateurs d'adresses A1 et A2 utilisent ensuite leurs paramètres de pas et d'incrément pour passer d'un pixel au suivant et d'une ligne à la suivante.

Le lancement effectif du Blitter est lié à B_CMD et à la séquence d'accès prescrite par la documentation matérielle. Une fois tous les paramètres préparés, l'écriture de la commande dans B_CMD, ou la séquence documentée correspondante, déclenche l'opération. À partir de cet instant, le Blitter utilise les registres précédemment configurés pour effectuer le traitement de manière autonome. Il faut donc éviter de modifier les registres nécessaires à l'opération pendant que celle-ci est encore en cours.

Avant de reconfigurer le Blitter ou de démarrer une nouvelle opération, le logiciel doit par conséquent tester son état busy. Tant que le matériel signale qu'il est occupé, certains registres peuvent encore être utilisés par l'opération précédente. Les modifier prématurément peut changer les paramètres au milieu d'un transfert et provoquer des résultats imprévisibles, comme une mauvaise adresse mémoire, une image corrompue ou des données Z incorrectes. Une séquence robuste consiste donc à attendre que le Blitter soit disponible avant de préparer les registres de l'opération suivante.

Une autre subtilité concerne les champs numériques du Blitter. Une valeur de zéro ne signifie pas nécessairement qu'aucun élément ne doit être traité. Pour certains champs matériels, zéro peut représenter la valeur maximale que le compteur est capable d'encoder. Il serait donc incorrect de considérer systématiquement un B_COUNT contenant un champ nul comme une opération sans effet (no-op). Le sens exact de zéro doit être déterminé selon le champ concerné et les règles définies par le matériel.

Le registre B_CMD constitue le cour de la programmation du Blitter, car ses différents bits sélectionnent les fonctions utilisées pendant l'opération. Ils déterminent notamment les sources de données, qui peuvent provenir de la mémoire, d'un motif (pattern) ou d'une opération d'addition. D'autres bits contrôlent la LFU (Logical Function Unit), qui permet de réaliser des combinaisons logiques entre les données sources et les données déjà présentes dans la destination.

B_CMD contrôle également les fonctions de comparaison et d'inhibition d'écriture. Une comparaison peut déterminer si un pixel doit réellement être écrit ou si l'écriture doit être bloquée. Des commandes spécifiques concernent aussi le Z-buffer : elles sélectionnent les comparaisons de profondeur à effectuer et déterminent si les valeurs Z doivent être écrites. Le même registre permet encore d'activer les fonctions nécessaires au Gouraud shading, de choisir la direction du parcours et de configurer certains comportements liés au traitement en mode pixel ou en mode phrase.

Comme de nombreuses fonctions indépendantes sont regroupées dans B_CMD, une simple erreur sur un bit peut complètement modifier le comportement du Blitter. Un bit incorrect peut, par exemple, demander au circuit de lire une source qui n'était pas censée être active, sélectionner une mauvaise opération logique, inverser le sens d'un transfert ou provoquer l'écrasement des valeurs du Z-buffer. Ces erreurs peuvent être particulièrement difficiles à diagnostiquer parce que la commande reste matériellement valide, mais ne correspond plus à l'opération voulue.

Pour limiter ces problèmes, il est préférable de construire les valeurs de B_CMD à partir de constantes symboliques représentant chacune une fonction précise plutôt que d'utiliser directement des valeurs hexadécimales difficiles à interpréter. Une commande peut alors être assemblée explicitement à partir des options désirées : sélection des sources, LFU, comparaison, inhibition, traitement Z, Gouraud, direction et autres paramètres. Cette méthode rend le programme beaucoup plus lisible et facilite également le développement d'un émulateur Jaguar, puisque chaque bit de commande peut être identifié, testé et comparé séparément au comportement attendu du véritable Blitter.

Blitter : Pixels, phrases, Z et Gouraud

Le Blitter de la console Atari Jaguar est un circuit matériel spécialisé dans les transferts et les opérations graphiques rapides. Il peut travailler selon un mode pixel ou un mode phrase. En mode pixel, il prend en charge différentes profondeurs de couleur, notamment 1, 2, 4, 8, 16 et 32 bits par pixel (bpp). Les pixels peuvent être regroupés ou « empaquetés » (packing) dans les mots mémoire afin d'utiliser efficacement l'espace disponible. Le Blitter doit donc interpréter correctement la profondeur sélectionnée pour déterminer la position et la taille de chaque pixel à l'intérieur des données manipulées.

Le mode phrase est particulièrement important pour obtenir les meilleures performances. Sur la Jaguar, une phrase correspond à une unité de données de 64 bits, soit 8 octets. Le Blitter peut ainsi transférer plusieurs pixels simultanément plutôt que de les traiter individuellement. Cette méthode permet d'exploiter beaucoup plus efficacement la bande passante de la mémoire. Pour obtenir le débit maximal, les adresses de base, les largeurs des surfaces et les différents pas ou incréments d'adressage doivent cependant respecter les alignements attendus. Des données mal alignées peuvent obliger le matériel à effectuer des accès supplémentaires et réduire considérablement l'avantage du mode phrase.

Une partie essentielle de la configuration du Blitter repose sur ses registres FLAGS. Ceux-ci contiennent plusieurs champs déterminant la manière dont les données graphiques sont interprétées et parcourues. Ils encodent notamment PITCH, qui participe à la définition de l'organisation et du pas des données en mémoire, PIXEL, qui indique le format ou la profondeur des pixels, ZOFFS, qui intervient dans la localisation des données associées au Z-buffer, ainsi que WIDTH, qui décrit la largeur de la surface selon le format attendu par le Blitter. D'autres bits contrôlent également la manière dont les coordonnées X et Y sont ajoutées ou modifiées pendant l'opération. Une configuration incorrecte de ces champs peut donc provoquer aussi bien une image déformée qu'un mauvais parcours de la mémoire.

Le Blitter possède également des fonctions matérielles destinées au Z-buffer, utilisé pour déterminer la visibilité des éléments graphiques selon leur profondeur. Pendant une opération, une valeur Z provenant de la source peut être comparée à la valeur Z déjà présente dans la destination. Les bits de contrôle sélectionnent les conditions de comparaison à appliquer. Selon le résultat obtenu, le Blitter peut décider d'écrire ou non la couleur du pixel. Il est notamment possible de bloquer l'écriture de la couleur tout en autorisant la mise à jour de la valeur Z, ce qui permet de réaliser certaines opérations de profondeur indépendamment de l'affichage effectif du pixel.

Le Blitter prend en charge le Gouraud shading, technique permettant d'obtenir des variations progressives de couleur ou d'intensité sur une surface. Plutôt que de calculer indépendamment la couleur de chaque pixel, le matériel part d'une valeur initiale et effectue une interpolation au moyen d'incréments au fur et à mesure qu'il progresse dans la ligne ou la surface. Les intensités ou composantes de couleur peuvent ainsi évoluer progressivement d'un pixel au suivant. Cette capacité réduit la quantité de calcul que le processeur ou le GPU doit effectuer pour produire des polygones présentant des dégradés réguliers.

Les informations de couleur et de profondeur Z peuvent également être organisées de manière entrelacée en mémoire. Cette disposition n'est pas uniquement une question de commodité : elle peut permettre de conserver les données nécessaires à l'intérieur d'une même page DRAM pendant les opérations du Blitter. Comme un changement de page mémoire peut entraîner une pénalité d'accès, une organisation judicieuse des données de couleur et de Z contribue à maintenir une meilleure bande passante. L'organisation physique des buffers en mémoire fait donc partie intégrante de l'optimisation du Blitter de la Jaguar.

Certaines situations demandent toutefois une attention particulière, notamment les limites d'un span, c'est-à-dire les extrémités d'une ligne ou d'une portion de ligne à dessiner. Le premier et le dernier pixel d'une opération peuvent ne pas correspondre exactement aux limites d'une phrase de 64 bits. Le Blitter doit alors employer des masques de phrase afin de modifier uniquement les pixels réellement concernés et de préserver les pixels voisins. Ces cas de bord sont particulièrement sensibles aux erreurs d'alignement, de largeur ou de calcul des coordonnées.

Pour cette raison, il est prudent de prévoir du padding autour des textures, c'est-à-dire quelques données ou pixels supplémentaires au-delà de leurs limites logiques. Cette marge peut éviter qu'un accès effectué à proximité d'une limite ne touche une zone mémoire indésirable. Une implémentation du Blitter, et particulièrement un émulateur de Jaguar, devrait également être testée avec plusieurs cas limites : des opérations d'une largeur d'un seul pixel, des fins de lignes non alignées sur une phrase, ainsi que des copies ou dessins effectués en direction inverse. Ces situations sollicitent précisément les mécanismes de masquage, d'incrémentation et de calcul d'adresse qui sont les plus susceptibles de révéler une erreur dans l'utilisation ou l'émulation du Blitter.

Interruptions TOM

Dans l'architecture de la Jaguar, la puce TOM joue un rôle central dans la gestion de plusieurs interruptions destinées au processeur principal Motorola 68000. TOM peut signaler au 68000 des événements provenant de cinq sources principales : le système vidéo, le GPU (Graphics Processing Unit), l'Object Processor (OP), la minuterie (timer) et le Blitter. Ces interruptions permettent au processeur de réagir à des événements matériels sans devoir vérifier continuellement l'état de chacun de ces composants. Elles sont notamment utilisées pour synchroniser le programme avec l'affichage vidéo, signaler la fin ou l'évolution d'un traitement graphique et réagir à l'expiration d'une minuterie.

Le contrôle de ces interruptions passe principalement par les registres INT1, situé à l'adresse $F000E0, et INT2, situé à l'adresse $F000E2. Le registre INT1 regroupe plusieurs fonctions liées aux interruptions de TOM : certains de ses bits permettent leur activation (enable), tandis que d'autres correspondent aux indicateurs mémorisés ou latches signalant qu'une source a demandé une interruption. Des bits permettent également d'effectuer leur acquittement ou effacement (clear). INT2 complète ce mécanisme de contrôle des interruptions. Il est donc important de considérer INT1 et INT2 comme faisant partie du système de gestion des interruptions de TOM plutôt que comme de simples registres d'état indépendants.

Lorsqu'une interruption est déclenchée, son traitement ne consiste pas uniquement à effacer un indicateur général dans TOM. La source matérielle de l'interruption doit elle aussi être acquittée dans son propre bloc matériel, puis l'interruption correspondante doit être acquittée au niveau de TOM. L'ordre de ces opérations est important : si la cause originale demeure active alors que l'indicateur de TOM est effacé, l'interruption peut être immédiatement redéclenchée. Le gestionnaire d'interruption doit donc identifier la source, traiter ou supprimer la condition qui l'a provoquée, effectuer l'acquittement nécessaire dans le périphérique concerné, puis mettre à jour correctement l'état de l'interruption dans TOM selon l'ordre prévu par le matériel.

Le GPU de la Jaguar possède également son propre mécanisme d'interruptions, distinct du système par lequel TOM interrompt directement le 68000. Plusieurs composants peuvent provoquer une interruption du GPU : le CPU, la puce JERRY, une minuterie, l'Object Processor et le Blitter. Le GPU peut ainsi être averti directement de certains événements matériels et exécuter un traitement approprié sans que toutes les opérations passent systématiquement par le programme principal exécuté par le Motorola 68000.

La gestion des interruptions du GPU présente toutefois une particularité importante. Le GPU travaille avec une RAM locale, dans laquelle sont placés son programme et ses gestionnaires d'interruptions. Les différentes sources d'interruption sont associées, selon les conventions matérielles et logicielles de la Jaguar, à des vecteurs ou à des adresses fixes dans cette mémoire locale. Le programmeur doit donc organiser correctement le code présent dans la RAM locale afin que, lorsqu'une interruption survient, le GPU puisse transférer l'exécution vers le gestionnaire correspondant sans écraser ou interpréter incorrectement d'autres données ou instructions.

Enfin, une précaution essentielle concerne le moment où les interruptions du GPU sont autorisées. Une interruption ne doit pas survenir pendant le chargement du code du GPU ou pendant une opération de changement de banque de code. Dans une telle situation, le contenu de la RAM locale peut être temporairement incomplet ou ne plus correspondre aux adresses attendues par les gestionnaires d'interruptions. Le GPU risquerait alors de sauter vers une adresse contenant du code partiellement chargé, des données ou le contenu d'une autre banque. En pratique, les interruptions concernées doivent donc être désactivées ou soigneusement contrôlées pendant ces opérations critiques, puis réactivées lorsque le code et les vecteurs nécessaires sont de nouveau dans un état cohérent.

JERRY : Vue générale

La puce JERRY constitue, avec TOM, l'un des deux principaux circuits personnalisés de la console Atari Jaguar. Alors que TOM concentre principalement les fonctions graphiques et vidéo, JERRY regroupe une grande partie des fonctions liées au son, au DSP, aux minuteries, aux communications série et aux entrées-sorties. Ses différents blocs matériels sont accessibles dans plusieurs régions de l'espace d'adressage du Motorola 68000.

La région comprise entre $F10000 et $F13FFF regroupe les principaux registres de JERRY. On y trouve notamment les fonctions associées aux horloges, aux minuterie, à l'UART et au système audio. Ces registres permettent au logiciel de configurer les temporisations, de générer ou de recevoir certains événements périodiques, de gérer les communications série et de contrôler le chemin utilisé pour produire le son de la console.

Les minuteries de JERRY peuvent notamment servir à générer des événements à intervalles déterminés et à provoquer des interruptions lorsqu'un compteur atteint la condition prévue. Ils constituent ainsi des ressources utiles pour synchroniser certaines tâches indépendamment du balayage vidéo. L'UART (Universal Asynchronous Receiver/Transmitter) fournit pour sa part les mécanismes nécessaires aux communications série prévues par l'architecture de la Jaguar.

Le sous-système audio de JERRY travaille étroitement avec le DSP. La Jaguar ne repose pas simplement sur un générateur sonore possédant un ensemble fixe de voix musicales. Le DSP peut produire et mélanger numériquement les échantillons, puis les transmettre au chemin audio de JERRY. Les registres de cette première région participent donc à la configuration des horloges et des interfaces nécessaires pour acheminer les données sonores vers la sortie.

La région $F14000-$F17FFF est principalement associée aux manettes de jeux, aux boutons et aux fonctions GPIO (General-Purpose Input/Output). Elle permet au programme de lire l'état des commandes utilisées par les joueurs et d'accéder aux lignes d'entrée-sortie prévues par le matériel. Les contrôleurs de la Jaguar possédant de nombreuses touches, leur lecture implique une organisation matérielle plus élaborée qu'un simple registre contenant un bit fixe pour chaque bouton.

La région comprise entre $F18000 et $F1AFFF est consacrée aux registres et au contrôle du DSP. Le DSP de JERRY est un processeur RISC programmable dont l'architecture est apparentée à celle du GPU de TOM. Ces registres permettent notamment au reste de la machine de contrôler son exécution, de consulter ou de modifier certains états et d'effectuer les opérations nécessaires au chargement et au démarrage de ses programmes.

Le DSP dispose de sa propre RAM locale de 8 Kio, située dans la région $F1B000-$F1CFFF. Cette mémoire rapide peut contenir le code exécuté par le DSP ainsi que les données critiques dont il a besoin. Comme pour la RAM locale du GPU, son intérêt principal est de réduire la dépendance envers la DRAM principale partagée. Les boucles de traitement audio, les buffers temporaires et les petites tables fréquemment consultées peuvent ainsi être conservés à proximité immédiate du processeur.

JERRY expose également une ROM wavetable dans la région $F1D000-$F1DFFF. Cette mémoire contient des données pouvant être exploitées pour la synthèse et certains traitements sonores. Elle complète les possibilités programmables du DSP en lui fournissant une ressource locale prédéfinie destinée notamment à la génération de formes d'onde.

Il faut cependant être prudent lorsqu'on accède aux différents périphériques de JERRY. Leur interface n'est pas uniformément organisée selon une largeur unique. Une grande partie de ces périphériques se trouve sur un chemin de données de 16 bits, mais certains registres ou périphériques ne sont effectivement accessibles que sur 8 bits. Le logiciel doit donc employer la largeur d'accès prévue pour chaque registre plutôt que de supposer que tous peuvent être lus ou écrits de la même manière.

Cette distinction est particulièrement importante avec le Motorola 68000, qui peut effectuer des accès de différentes tailles. Utiliser une largeur incorrecte pour un registre matériel peut lire des informations non pertinentes, modifier un registre voisin ou produire un comportement différent de celui attendu. Un émulateur doit lui aussi reproduire correctement ces restrictions afin que les programmes utilisant des accès 8 ou 16 bits se comportent comme sur la console réelle.

Enfin, les alias d'adresses et les offsets exacts des registres doivent être déterminés à partir de la révision appropriée de la liste officielle des registres. Certaines documentations ou révisions du matériel peuvent présenter des particularités d'adressage, des alias ou des différences de nomenclature. Il est donc préférable de ne pas déduire automatiquement une adresse à partir du seul nom d'un registre : le programmeur ou l'auteur d'un émulateur doit suivre la register list correspondant au matériel documenté.

JERRY peut ainsi être considéré comme le principal centre audio et d'entrée-sortie programmable de la Jaguar. La zone $F10000-$F13FFF rassemble les horloges, timers, UART et fonctions audio, $F14000-$F17FFF les contrôleurs et GPIO, $F18000-$F1AFFF le contrôle du DSP, $F1B000-$F1CFFF ses 8 Kio de RAM locale, et $F1D000-$F1DFFF la ROM wavetable. L'utilisation correcte de ces régions exige toutefois de respecter la largeur réelle de chaque périphérique ainsi que les adresses, offsets et alias définis par la documentation matérielle.

Adresse Description
$F10000-$F13FFF Registres Jerry : horloges, minuteries, UART, audio
$F14000-$F17FFF Manettes de jeux, boutons et GPIO
$F18000-$F1AFFF Registres/contrôle DSP
$F1B000-$F1CFFF RAM locale DSP, 8 Kio
$F1D000-$F1DFFF ROM wavetable

DSP : Architecture et mémoire

Le DSP (Digital Signal Processor) de la console Atari Jaguar est un processeur RISC intégré à la puce JERRY. Son architecture est étroitement apparentée à celle du GPU présent dans TOM : les deux processeurs partagent une grande partie du même cour RISC et plusieurs principes de fonctionnement. Le DSP est toutefois adapté davantage au traitement numérique du signal, en particulier à l'audio, alors que le GPU possède des fonctions plus directement orientées vers les traitements graphiques.

Comme le GPU, le DSP possède 64 registres organisés en deux banques de 32 registres. Une banque constitue l'ensemble actif tandis que l'autre peut être utilisée comme banque alternative, notamment dans le contexte de certaines interruptions. Cette organisation fournit suffisamment de registres pour conserver des échantillons, adresses, compteurs, coefficients et résultats intermédiaires sans devoir effectuer continuellement des accès à la mémoire.

Le DSP utilise également une architecture pipeline. Plusieurs étapes appartenant à différentes instructions peuvent donc être en cours simultanément. Cette organisation améliore le débit d'exécution, mais elle impose les mêmes précautions générales que sur le GPU concernant les dépendances entre instructions et les latences. Certaines valeurs ne deviennent pas immédiatement disponibles après leur production et le programme doit respecter les règles de pipeline prévues pour le coeur RISC.

Le système d'interruptions du DSP est lui aussi comparable à celui du GPU. Le processeur peut réagir à différents événements matériels et utiliser ses banques de registres pour faciliter le changement de contexte. Son fonctionnement général est également contrôlé par des mécanismes semblables autour de RUN et PC : PC détermine l'adresse du code à exécuter, tandis que le contrôle RUN permet d'arrêter ou de démarrer l'exécution. Le chargement et l'initialisation d'un programme DSP suivent donc des principes proches de ceux employés avec le GPU.

Malgré cette parenté, le DSP n'est pas simplement une copie exacte du GPU placée dans JERRY. Il possède des fonctions supplémentaires adaptées au traitement du signal, notamment des opérations MAC (Multiply-Accumulate). Une opération MAC combine une multiplication et une accumulation, ce qui est particulièrement utile dans de nombreux algorithmes audio tels que le mélange, le filtrage et certaines transformations numériques où des produits doivent être additionnés successivement.

Le DSP ajoute également des fonctions d'adressage modulo. Celles-ci sont particulièrement utiles pour manipuler des tampons circulaires, car elles permettent de faire revenir automatiquement une adresse au début d'une zone lorsque la fin est atteinte. Dans un moteur audio, ce mécanisme facilite la gestion de flux continus d'échantillons sans obliger le programme à vérifier manuellement la limite du tampon après chaque accès.

Une autre capacité particulière concerne les opérations de mirror, qui permettent d'effectuer certains réarrangements ou transformations de bits utiles aux algorithmes de traitement numérique. Ces fonctions peuvent notamment simplifier des opérations dans lesquelles l'ordre des bits doit être inversé ou réorganisé, évitant d'avoir à reproduire entièrement ce traitement avec une longue suite d'instructions élémentaires.

Le DSP possède en outre des fonctions de saturation, particulièrement adaptées à l'audio. Dans une arithmétique ordinaire, un dépassement de capacité peut provoquer un retour de la valeur à l'autre extrémité de l'intervalle numérique. Pour des échantillons sonores, ce comportement peut créer des erreurs très importantes. L'arithmétique saturée permet au contraire de limiter le résultat à la valeur minimale ou maximale représentable lorsque celui-ci dépasse l'intervalle autorisé.

En contrepartie de ces fonctions orientées vers le traitement numérique du signal, le DSP ne possède pas nécessairement toutes les instructions spécialisées disponibles sur le GPU pour les traitements graphiques. Les deux processeurs doivent donc être considérés comme deux variantes d'un même coeur RISC, chacune adaptée à son domaine principal : le GPU aux calculs et à l'orchestration graphique, le DSP aux opérations de traitement du signal et particulièrement au son.

Le DSP dispose d'une RAM locale de 8 Kio, accessible dans la région $F1B000-$F1CFFF. Cette mémoire locale est deux fois plus importante que les 4 Kio associés au GPU et constitue l'espace privilégié pour le code et les données nécessitant des accès rapides. Sa proximité avec le DSP permet d'éviter une grande partie des délais et de la contention associés à la DRAM principale partagée.

Ces 8 Kio sont suffisamment importants pour accueillir un mixer audio, différentes tables de calcul et de petits tampons. Le programmeur peut ainsi placer dans la RAM locale les boucles critiques chargées du mélange des canaux, les coefficients nécessaires à certains traitements, les variables fréquemment utilisées et une partie des échantillons temporaires. Une organisation judicieuse de cette mémoire contribue directement à la régularité du traitement audio.

JERRY contient également une ROM wavetable, située dans la région $F1D000-$F1DFFF. Cette ROM fournit des formes d'onde et des données utiles que le DSP peut exploiter dans ses traitements. Elle constitue donc une ressource supplémentaire disponible sans devoir occuper une partie de la RAM locale ou de la DRAM principale avec certaines données prédéfinies.

Le DSP n'est toutefois pas limité à sa RAM locale et à cette ROM. Il peut également lire des données dans la DRAM principale de la Jaguar. Cette possibilité est indispensable lorsque les échantillons audio, les musiques ou les autres ressources dépassent largement les 8 Kio disponibles localement. Le DSP peut ainsi récupérer en mémoire principale les données nécessaires, les traiter et produire le flux sonore demandé.

Ces accès à la DRAM doivent cependant être organisés avec précaution. La mémoire principale est partagée avec le Motorola 68000, le GPU, le Blitter, l'Object Processor et les autres moteurs matériels. Un accès du DSP peut donc subir de la contention lorsque plusieurs unités réclament simultanément le bus ou la mémoire. Contrairement à certains traitements graphiques qui peuvent parfois tolérer un retard ponctuel, le son doit être produit selon un rythme régulier.

Le flux audio doit par conséquent éviter les contentions importantes et surtout les stalls de durée non bornée. Si le DSP attend trop longtemps des données situées en DRAM, il risque de ne plus fournir les nouveaux échantillons au moment où le système audio les réclame. Cela peut provoquer une interruption du flux, des répétitions, des valeurs incorrectes ou d'autres artefacts sonores. Le traitement audio doit donc être conçu avec des contraintes de temps réel à l'esprit.

Une stratégie efficace consiste à conserver dans la RAM locale de 8 Kio le code critique, les tables fréquemment utilisées et de petits tampons permettant d'absorber les variations de temps d'accès, tout en utilisant la DRAM pour les ressources plus volumineuses. Le DSP peut alors effectuer le travail essentiel à partir de sa mémoire rapide et organiser les transferts avec la mémoire principale de manière suffisamment prévisible.

Le DSP de JERRY doit ainsi être compris comme un processeur RISC spécialisé pour le traitement numérique du signal, dérivé du même coeur général que le GPU mais enrichi de fonctions telles que MAC, modulo, mirror et saturation, et dépourvu de certaines instructions graphiques propres au GPU. Ses deux banques de registres, son pipeline, ses interruptions et ses mécanismes RUN/PC lui donnent une organisation familière pour qui connaît le GPU, tandis que ses 8 Kio de RAM locale, sa ROM wavetable et son accès à la DRAM lui fournissent les ressources nécessaires pour construire un moteur audio programmable et efficace.

Audio et interface série

Le système audio de la console Atari Jaguar se distingue de celui de nombreuses consoles plus anciennes par l'absence d'un synthétiseur musical matériel fixe comparable à un PSG (Programmable Sound Generator). JERRY ne fournit donc pas simplement un ensemble prédéfini de canaux matériels produisant automatiquement des formes d'onde déterminées. Une grande partie de la génération sonore est confiée au DSP, ce qui rend le système audio beaucoup plus programmable, mais impose également au logiciel d'effectuer lui-même une part importante du traitement.

Le DSP de JERRY peut ainsi générer ou mélanger différents types de sons en logiciel. Il peut travailler avec des échantillons PCM, utiliser des données de wavetable, réaliser une synthèse de type FM ou calculer différents effets sonores. Ces possibilités ne représentent pas nécessairement des générateurs matériels indépendants intégrés à JERRY : elles résultent principalement des algorithmes exécutés par le DSP. Le moteur audio d'un jeu peut donc être adapté aux besoins du programme plutôt que d'être limité à une architecture sonore entièrement prédéterminée.

Après avoir calculé et mélangé les différentes sources, le DSP produit les échantillons stéréo destinés à la sortie. Il fournit séparément les informations correspondant aux canaux gauche et droit, puis écrit ces échantillons vers l'interface série audio et le DAC de JERRY. Le DSP assure ainsi la génération numérique du flux, tandis que les circuits de sortie prennent en charge son acheminement et sa conversion vers le domaine analogique.

La cadence à laquelle les données audio sont transmises est programmable grâce aux mécanismes d'horloge de JERRY, notamment SCLK et SMODE. Ces paramètres contrôlent le fonctionnement de l'interface série et déterminent le rythme auquel les échantillons doivent être fournis. Le programme audio doit donc être synchronisé avec cette cadence : une fois l'interface configurée, de nouvelles valeurs doivent être produites suffisamment régulièrement pour maintenir un flux sonore continu.

La production des échantillons peut être organisée autour d'un gestionnaire périodique (handler) ou d'une boucle exécutée par le DSP. À chaque période appropriée, le moteur calcule ou récupère les valeurs nécessaires pour les canaux gauche et droit, effectue éventuellement le mélange des différentes voix et transmet le résultat au système de sortie. Les échantillons produits sont souvent codés sur 16 bits, ce qui fournit une précision suffisante pour le flux audio final tout en restant pratique à manipuler par le DSP.

Le DSP peut, par exemple, maintenir plusieurs voix logicielles représentant la musique et les effets sonores. Pour chaque nouvel échantillon de sortie, il récupère les valeurs correspondant aux différentes sources, applique leurs volumes ou d'autres transformations, les additionne et produit une valeur finale pour le canal gauche ainsi qu'une autre pour le canal droit. Les fonctions spécialisées du DSP, notamment les opérations MAC et de saturation, sont particulièrement adaptées à ce genre de traitement.

Une fois les données numériques transmises, le DAC (Digital-to-Analog Converter) transforme les échantillons en un signal analogique. Les filtres analogiques présents sur le chemin de sortie participent ensuite aux caractéristiques finales du signal sonore. Le DSP détermine donc le contenu numérique des échantillons, mais le DAC et les filtres fixent également certaines propriétés de la sortie réellement obtenue sur le matériel.

Les sons utilisés par un jeu ne doivent pas nécessairement être stockés sous forme PCM non compressée. Les échantillons provenant d'une cartouche ou du CD peuvent, par exemple, être encodés en ADPCM ou employer d'autres méthodes de compression prises en charge par le logiciel. Cette possibilité permet de réduire l'espace nécessaire au stockage des ressources sonores, au prix d'un travail de décodage supplémentaire pendant l'exécution.

Il faut cependant souligner que JERRY ne possède pas de décodeur universel capable de reconnaître et de décompresser automatiquement tous ces formats. Si un jeu utilise de l'ADPCM ou un autre format compressé, le décodage doit être effectué par le logiciel, généralement à l'aide du DSP ou d'un autre processeur selon l'organisation choisie. La présence du DSP rend cette approche possible, mais le format de compression et l'algorithme de décodage restent sous la responsabilité du programme.

Le caractère temps réel de l'audio impose par ailleurs une contrainte essentielle : l'interface série doit recevoir ses données avant d'en manquer. Une sous-alimentation du FIFO ou du chemin série, c'est-à-dire l'absence d'un nouvel échantillon au moment où celui-ci est requis, peut provoquer la répétition d'une valeur précédente, un clic ou d'autres artefacts audibles. Contrairement à un calcul graphique qui peut parfois simplement terminer un peu plus tard, un échantillon audio manquant ne peut pas être livré après coup sans affecter le flux sonore.

Cette contrainte devient particulièrement importante parce que le DSP peut devoir récupérer des échantillons ou d'autres données dans la DRAM principale partagée. Au même moment, l'Object Processor peut lire les données nécessaires à l'affichage et le Blitter peut effectuer des transferts ou des opérations graphiques intensives. La contention qui en résulte peut retarder les accès mémoire du DSP et menacer la régularité de l'alimentation audio.

Pour éviter ce problème, un moteur audio robuste peut employer un double buffering. Pendant qu'un tampon contient les échantillons actuellement consommés par le système de sortie, le DSP prépare le tampon suivant. Une fois le premier suffisamment avancé ou terminé, les rôles sont échangés. Cette technique fournit une réserve de données et réduit le risque qu'une courte période de contention mémoire interrompe immédiatement le son.

Les interruptions (IRQ) peuvent également servir à synchroniser le renouvellement des données audio. Le gestionnaire correspondant doit cependant être conçu de manière à respecter une borne temporelle garantie. Autrement dit, le programme doit pouvoir assurer que les prochains échantillons seront disponibles dans un délai maximal connu, même lorsque l'Object Processor ou le Blitter sollicite fortement la DRAM.

Le système audio de la Jaguar repose donc sur une coopération entre le DSP programmable, l'interface série de JERRY, ses horloges SCLK/SMODE, le DAC et le chemin analogique. Cette architecture offre une grande liberté : PCM, wavetable, FM, effets et formats compressés peuvent être réalisés par logiciel. En contrepartie, le programme doit maintenir un flux stéréo régulier, généralement constitué d'échantillons 16 bits, et utiliser une stratégie de buffering et d'interruptions suffisamment robuste pour empêcher toute sous-alimentation du chemin audio, même lorsque les circuits graphiques occupent intensivement la mémoire partagée.

Minuteries, horloges et UART

La puce JERRY de la console Atari Jaguar ne se limite pas au DSP et aux fonctions directement consacrées à la production du son. Elle contient également plusieurs ressources permettant de gérer le temps et certaines communications avec le reste du matériel. Parmi celles-ci figurent deux minuteries programmables, des prescalers, un mécanisme d'interruptions, différentes horloges audio, une interface UART ainsi que des lignes GPIO utilisées pour communiquer avec certains périphériques de la console.

JERRY possède ainsi deux minuteries matériels programmables. Ces minuteries permettent au logiciel de mesurer ou de produire des intervalles temporels sans devoir utiliser une boucle d'attente exécutée continuellement par le Motorola 68000 ou le DSP. Elles peuvent notamment servir à déclencher périodiquement certaines opérations, à synchroniser une tâche ou à provoquer une interruption lorsqu'un compteur atteint la condition prévue.

Les minuteries ne comptent pas nécessairement directement les cycles de l'horloge principale de la Jaguar. Ils travaillent à partir d'horloges dérivées, dont la fréquence peut être adaptée au moyen de prescalers. Un prescaler divise ou transforme la cadence de référence avant qu'elle soit appliquée au compteur. Cette organisation permet d'obtenir des périodes beaucoup plus longues que celles que permettrait un compteur alimenté directement à la fréquence système.

La durée produite par une minuterie dépend donc de la combinaison entre la fréquence de l'horloge dérivée, le réglage du prescaler et la valeur chargée dans le compteur. Pour programmer correctement une période, il faut tenir compte de toute cette chaîne plutôt que de considérer la valeur de la minuterie comme un nombre direct de cycles du processeur. Une mauvaise hypothèse sur l'horloge d'entrée peut produire une fréquence d'interruption très différente de celle recherchée.

Les minuteries peuvent être associées au système d'interruptions. Lorsqu'une minuterie atteint l'événement prévu, il peut signaler cette condition au processeur concerné afin qu'un gestionnaire soit exécuté. Le programme peut ainsi effectuer une opération à intervalles réguliers sans tester constamment l'état du compteur. Ce mécanisme est particulièrement utile pour les traitements qui doivent être déclenchés selon une cadence relativement précise.

Il faut cependant respecter la sémantique matérielle du zéro, du rechargement et de l'acquittement. Une valeur nulle dans un compteur ou un registre de période ne doit pas automatiquement être interprétée comme signifiant « timer désactivé » ou « aucune attente ». Selon le mécanisme matériel, zéro peut correspondre à un état particulier du compteur ou intervenir dans le cycle de rechargement. Le comportement exact doit donc suivre les règles documentées pour JERRY.

Le rechargement (reload) détermine la manière dont une minuterie recommence son comptage après avoir atteint sa condition terminale. Selon la configuration, la valeur utilisée par le timer peut être réintroduite afin de produire des événements périodiques. La relation entre la valeur programmée, le passage par zéro et le rechargement doit être reproduite exactement, en particulier dans un émulateur, car une différence d'un cycle peut progressivement désynchroniser un événement périodique.

De même, une interruption générée par une minuterie doit être acquittée selon la procédure prévue par le matériel. Il ne suffit pas nécessairement d'exécuter le gestionnaire et d'en revenir. Si la condition d'interruption reste active ou si son indicateur n'est pas effacé correctement, le processeur peut recevoir immédiatement une nouvelle interruption. L'ordre des opérations d'acquittement doit donc respecter le comportement de JERRY et celui du contrôleur d'interruptions concerné.

JERRY fournit également les horloges nécessaires au sous-système audio. Ces horloges participent notamment à la définition de la cadence à laquelle les échantillons sont transmis par l'interface série vers le système de conversion audio. Elles sont donc essentielles au maintien d'un flux sonore régulier. La fréquence de sortie audio ne dépend pas simplement de la vitesse d'exécution du DSP, mais également de la configuration de ces générateurs d'horloge.

L'UART (Universal Asynchronous Receiver/Transmitter) de JERRY fournit pour sa part un mécanisme de communication série. Il peut être utilisé dans certains contextes de développement ou pour des liaisons prévues par l'architecture. Cette interface est particulièrement utile lorsqu'un système de développement doit échanger des informations avec la Jaguar, par exemple pour certaines communications, opérations de diagnostic ou interactions avec du matériel externe approprié.

Il ne faut toutefois pas considérer cet UART comme l'équivalent d'un port série utilisateur standard et entièrement disponible sur toutes les consoles Jaguar. La présence du circuit dans JERRY ne signifie pas nécessairement que toutes ses lignes sont exposées sous la forme d'un connecteur utilisateur universel directement exploitable. Son accessibilité pratique dépend de la configuration matérielle et du contexte dans lequel la console est utilisée.

Les fonctions GPIO (General-Purpose Input/Output) complètent ces interfaces. Elles permettent à JERRY de lire ou de piloter certains signaux numériques qui ne correspondent pas nécessairement à une fonction aussi spécialisée que l'UART ou l'audio. Dans la Jaguar, ces lignes servent notamment à gérer des signaux associés à la cartouche et au système CD. Elles participent donc aux échanges de contrôle entre la console et certains matériels qui lui sont raccordés.

Il est possible d'envisager l'utilisation d'une minuterie de JERRY pour rythmer une tâche audio, par exemple en provoquant périodiquement une interruption destinée au DSP. Cette solution n'est cependant correcte que si les caractéristiques temporelles du timer et du système d'interruptions correspondent aux exigences du flux sonore.

Le DSP peut en effet recevoir plusieurs sources d'interruption, et celles-ci doivent être traitées selon leurs priorités et leurs contraintes de pipeline. Une interruption provenant d'un timer peut être retardée si une autre IRQ est déjà en cours de traitement ou possède une priorité incompatible avec la cadence recherchée. Pour une tâche audio, ce retard peut devenir problématique si les prochains échantillons doivent être fournis dans un délai strict.

Une minuterie ne doit donc être utilisé pour piloter directement le son que si sa priorité et sa latence maximale restent compatibles avec les autres interruptions du DSP. Le moteur audio doit garantir que le traitement périodique sera exécuté suffisamment tôt pour éviter une sous-alimentation de l'interface série. Dans le cas contraire, il est préférable d'organiser autrement la synchronisation ou de prévoir suffisamment de buffering pour absorber les variations de latence.

Les minuteries, horloges, UART et GPIO de JERRY forment ainsi un ensemble de fonctions de temporisation et d'entrée-sortie qui complètent le DSP et le système audio. Leur programmation demande cependant de respecter précisément le fonctionnement matériel : origine des clocks, prescalers, passage par zéro, rechargement, acquittement des interruptions et priorités des IRQ. Ces détails deviennent particulièrement importants lorsque les minuteries participent à une tâche temps réel comme la production audio.

Contrôleurs et clavier numérique

La manette standard de l'Atari Jaguar se distingue de nombreux contrôleurs de consoles contemporaines par le nombre important de commandes qu'elle propose. Elle comporte une croix directionnelle à huit directions, trois boutons d'action principaux A, B et C, ainsi que les boutons Pause et Option. À ces commandes s'ajoute un clavier numérique de 12 touches, composé des chiffres 0 à 9 et des touches * et #. Ce clavier fait partie intégrante du contrôleur et peut être utilisé directement par les jeux.

La croix directionnelle permet de représenter les quatre directions principales ainsi que leurs combinaisons diagonales, d'où les huit directions disponibles pour le logiciel. Les boutons A, B et C servent généralement aux actions principales du jeu, tandis que Pause et Option possèdent des fonctions distinctes. Ils ne doivent donc pas être assimilés à de simples touches supplémentaires du clavier numérique, même si le système de lecture du contrôleur repose largement sur une organisation matricielle.

Le clavier à 12 touches constitue une caractéristique importante de la Jaguar. Plusieurs jeux l'utilisent pour sélectionner des armes, des objets, des fonctions ou des commandes qui auraient nécessité des menus supplémentaires avec une manette plus conventionnelle. Certains titres étaient d'ailleurs fournis avec des overlays, c'est-à-dire des cartes imprimées que l'on plaçait sur le clavier afin d'indiquer la fonction attribuée à chacune de ses touches dans le jeu.

Le ProController étend encore les possibilités de la manette Jaguar. Il ajoute notamment les boutons X, Y et Z, ainsi que les gâchettes L et R et d'autres commandes supplémentaires. Ces nouvelles entrées ne reposent pas sur un contrôleur totalement indépendant : elles réutilisent et étendent la matrice de lecture employée par le système des manettes. Un logiciel ou un émulateur doit donc tenir compte de cette organisation pour différencier correctement une manette standard d'un ProController.

Du côté matériel, les contrôleurs sont accessibles à travers des registres situés autour de $F14000, notamment JOYSTICK et JOYBUTS. La lecture des manettes n'est pas réalisée au moyen d'un registre contenant simplement un bit permanent pour chacune des nombreuses touches. Le système utilise une matrice multiplexée, ce qui permet de représenter un grand nombre de commandes avec un nombre plus limité de lignes électriques.

Le principe consiste à sélectionner certaines lignes de la matrice, puis à lire l'état des colonnes correspondantes. Le programme écrit donc un motif de sélection approprié dans le registre concerné, puis lit les bits retournés afin de savoir quelles commandes appartenant à cette partie de la matrice sont actuellement pressées. Une seule lecture ne permet pas nécessairement de connaître l'état de toutes les touches.

Les entrées sont en outre actives à l'état bas (active low). Cela signifie qu'un bit à zéro peut indiquer qu'une touche ou une direction sélectionnée est effectivement activée, tandis qu'un bit à un correspond normalement à son état inactif. Cette convention doit être prise en compte lors de l'interprétation des valeurs de JOYSTICK et JOYBUTS; inverser cette logique ferait apparaître des touches relâchées comme pressées et inversement.

Pour connaître l'état complet d'un contrôleur, le logiciel doit effectuer un balayage de plusieurs motifs de sélection. Il active successivement différentes lignes de la matrice et lit, pour chacune, les colonnes correspondantes. Les résultats de ces différentes lectures sont ensuite combinés afin de reconstruire l'état complet de la croix directionnelle, des boutons d'action, de Pause, d'Option et des douze touches du clavier numérique.

Les deux ports de contrôleurs de la Jaguar sont eux-mêmes multiplexés dans les mots des registres. Les informations des deux manettes peuvent donc apparaître dans différentes portions des valeurs lues. Le programme doit appliquer les masques appropriés pour séparer les entrées du premier joueur de celles du second tout en tenant compte du motif de matrice actuellement sélectionné.

Cette organisation possède des conséquences importantes pour l'émulation. Un émulateur Jaguar ne devrait pas représenter la manette comme un périphérique simplifié ne contenant que la croix et les boutons A, B et C. Une telle implémentation pourrait suffire pour quelques titres, mais elle rendrait partiellement ou totalement inutilisables les jeux qui exploitent le clavier numérique, Pause, Option ou les commandes supplémentaires du ProController.

Le clavier numérique doit notamment être entièrement exposé à l'utilisateur, puisque de nombreux jeux Jaguar utilisent ses touches et leurs overlays comme partie intégrante de leur interface. L'émulateur peut permettre d'associer les touches 0 à 9, * et # au clavier de l'ordinateur, à une manette moderne ou à une interface virtuelle. Il doit néanmoins présenter au logiciel émulé les mêmes états matriciels que ceux qu'aurait produits un véritable contrôleur.

Les boutons Pause et Option doivent également rester distincts. Même s'ils peuvent être intégrés au même mécanisme général de balayage, ils représentent deux commandes logiques différentes pour les jeux. Les fusionner ou les traiter comme des synonymes empêcherait certains logiciels de reconnaître correctement les actions prévues.

Enfin, une émulation fidèle doit prendre en considération les combinaisons simultanées de touches et, dans une mesure raisonnable, les phénomènes de ghosting pouvant résulter d'une matrice de clavier. Lorsque plusieurs lignes et colonnes sont activées simultanément, une véritable matrice électrique peut présenter des comportements qui ne correspondent pas simplement à une liste indépendante de boutons booléens. Il n'est pas nécessaire de transformer chaque lecture en simulation électrique extrêmement complexe, mais les combinaisons utilisées normalement par les jeux doivent être reproduites de manière cohérente.

Le système de contrôleurs de la Jaguar doit donc être considéré comme une matrice multiplexée complète plutôt que comme une manette traditionnelle à quelques boutons. Le logiciel sélectionne successivement des lignes par l'intermédiaire de registres tels que JOYSTICK et JOYBUTS, lit des colonnes actives à l'état bas, puis rassemble les résultats pour connaître toutes les commandes des deux ports. Cette architecture permet de prendre en charge aussi bien la manette standard avec son clavier à 12 touches que le ProController et ses boutons supplémentaires.

EEPROM de cartouche

Certaines cartouches de l'Atari Jaguar contiennent une petite mémoire non volatile de type EEPROM (Electrically Erasable Programmable Read-Only Memory). Cette mémoire permet au jeu de conserver des informations même lorsque la console est éteinte et que la cartouche est retirée. Elle peut notamment être utilisée pour enregistrer des scores, des paramètres, des données de progression ou des sauvegardes de parties, selon les besoins du logiciel.

L'EEPROM ne doit cependant pas être considérée comme une mémoire ordinaire directement intégrée à l'espace d'adressage du Motorola 68000. Il s'agit généralement d'un composant série avec lequel le logiciel communique en manipulant certaines lignes de contrôle. Sur la Jaguar, ces lignes sont pilotées au moyen de bits associés aux GPIO et à l'interface de la cartouche. Le programme doit donc produire la séquence de signaux attendue par le composant pour lire ou modifier son contenu.

Le dialogue avec l'EEPROM utilise un protocole série. Une transaction comporte typiquement une condition ou séquence de départ (start), suivie des informations nécessaires pour sélectionner l'opération et l'adresse concernée. Les données sont ensuite transmises ou reçues selon qu'il s'agit d'une écriture ou d'une lecture. Le composant peut également produire un signal d'acquittement (acknowledge) permettant au logiciel de vérifier qu'une partie de la transaction a bien été reconnue.

Le détail exact du protocole dépend du modèle d'EEPROM installé dans la cartouche. Le nombre de bits d'adresse, la capacité totale, l'organisation des données, les limites d'écriture et certaines séquences de commandes peuvent varier d'un composant à l'autre. Une implémentation correcte doit donc reproduire les caractéristiques du composant réellement utilisé plutôt que de supposer que toutes les cartouches Jaguar possèdent une EEPROM identique.

Une caractéristique importante de cette technologie est qu'une écriture n'est pas instantanée. Une fois les données série reçues, l'EEPROM doit effectuer physiquement son cycle interne de programmation. Pendant cette période, le composant peut être occupé (busy) et ne pas accepter immédiatement une nouvelle commande normale. Le logiciel doit donc respecter le délai d'écriture prévu et vérifier, lorsque le protocole le permet, que le composant est de nouveau disponible avant de poursuivre.

Il faut également respecter la taille des pages d'écriture. Certaines EEPROM permettent de programmer plusieurs octets au cours d'une même transaction, mais seulement à l'intérieur d'une page de taille déterminée. Une écriture qui franchit incorrectement cette limite peut produire un comportement différent de celui attendu, par exemple revenir au début de la page ou modifier des emplacements non prévus selon le composant. Le code de sauvegarde doit donc découper correctement ses écritures.

L'EEPROM possède par ailleurs une endurance d'écriture limitée. Même si elle peut être reprogrammée un très grand nombre de fois, chaque cellule ne supporte pas un nombre absolument illimité de cycles d'effacement et d'écriture. Un jeu doit donc éviter d'enregistrer continuellement des données sans nécessité. Il est préférable de regrouper les modifications et de n'effectuer une écriture que lorsque les informations persistantes ont réellement changé.

La valeur d'un emplacement effacé ou non programmé doit également être reproduite conformément au composant utilisé. Une EEPROM neuve ne doit pas nécessairement être initialisée arbitrairement avec des zéros. Le logiciel peut se servir de la valeur effacée pour déterminer qu'aucune sauvegarde n'existe encore, initialiser ses structures ou reconnaître une zone inutilisée. Cette valeur fait donc partie du comportement matériel que doit respecter une implémentation fidèle.

Dans un émulateur Jaguar, l'EEPROM doit être représentée comme une mémoire persistante distincte pour chaque jeu qui en possède une. Son contenu peut être enregistré dans un fichier de sauvegarde propre à la cartouche, puis rechargé lorsque le même jeu est lancé ultérieurement. L'émulateur reproduit ainsi la propriété essentielle de l'EEPROM réelle : les données restent disponibles entre deux sessions.

La sauvegarde de ce fichier devrait être réalisée de manière atomique afin de limiter le risque de corruption. Une méthode courante consiste à écrire d'abord le nouveau contenu dans un fichier temporaire, à s'assurer que l'opération s'est correctement terminée, puis à remplacer la sauvegarde précédente. Une interruption de l'émulateur ou une erreur pendant l'écriture a ainsi moins de chances de détruire simultanément l'ancienne et la nouvelle copie des données.

L'émulateur doit également reproduire le temps d'écriture et l'état busy au niveau du matériel émulé, même si l'écriture du fichier sur l'ordinateur hôte est pratiquement instantanée. Un jeu peut dépendre du délai réel de l'EEPROM ou interroger son état pour déterminer si une programmation est terminée. Valider immédiatement toutes les écritures pourrait donc masquer des erreurs ou produire un comportement différent de celui d'une véritable cartouche.

Enfin, toutes les cartouches Jaguar ne possèdent pas nécessairement une EEPROM. Lorsqu'une cartouche n'en contient pas, l'émulateur doit représenter une EEPROM absente, plutôt que de fournir systématiquement une mémoire de sauvegarde virtuelle à tous les jeux. Les lectures, écritures et signaux associés doivent alors correspondre au comportement d'une cartouche dépourvue de ce composant.

L'EEPROM de cartouche constitue donc un petit sous-système de stockage persistant dont le fonctionnement doit être traité comme celui d'un véritable périphérique série. Les lignes GPIO/cartouche assurent le dialogue, le protocole gère le départ, l'adresse, les données et les acquittements, tandis que les écritures doivent respecter le délai busy, la taille des pages, l'endurance et la valeur effacée du composant. Dans un émulateur, ces propriétés doivent être conservées tout en assurant une sauvegarde atomique dans un fichier distinct pour chaque jeu, uniquement lorsque la cartouche émulée possède réellement une EEPROM.

Cartouches et connecteur

La cartouche constitue le principal support de distribution des jeux de la console Atari Jaguar. Elle est reliée directement au système par un connecteur qui expose une partie importante du bus de la machine. Une cartouche peut ainsi contenir non seulement la ROM du programme et ses données, mais également certains composants supplémentaires, comme une EEPROM, de la RAM, une logique de mapping ou encore des circuits permettant de travailler avec d'autres extensions matérielles.

Dans la cartographie mémoire de la Jaguar, la principale fenêtre réservée à la ROM de cartouche, souvent appelée ROM1, s'étend de $800000 à $DFFFFF. Cette plage représente un espace d'adressage total de 6 Mio. Il s'agit d'une fenêtre disponible dans l'espace mémoire de la console et non d'une indication selon laquelle toutes les cartouches possèdent nécessairement 6 Mio de ROM.

Les cartouches commerciales utilisent en effet fréquemment des capacités plus petites, notamment 2 ou 4 Mio. La taille physique de la ROM dépend du jeu et de la quantité de code, de graphismes, de sons et d'autres données qu'il doit contenir. Une cartouche n'a donc pas besoin d'occuper la totalité de la fenêtre $800000-$DFFFFF; la logique matérielle et la disposition de la ROM déterminent quelles parties de cette fenêtre correspondent réellement aux composants présents.

Il est également important de distinguer la largeur du bus utilisé par la cartouche de celle associée à la mémoire principale. La Jaguar est connue pour son architecture capable d'exploiter des transferts DRAM de 64 bits, notamment sous forme de phrases utilisées par certains moteurs de TOM. Cela ne signifie toutefois pas que la ROM de cartouche est elle aussi nécessairement reliée au système par un chemin de 64 bits.

Le bus ROM de la console est typiquement utilisé avec une largeur de 32 bits pour les cartouches, malgré le chemin DRAM de 64 bits disponible ailleurs dans l'architecture. Cette différence explique pourquoi il faut éviter de déduire les caractéristiques du connecteur de cartouche à partir de la seule appellation « 64 bits » de la Jaguar. La largeur effective dépend du sous-système mémoire concerné.

Les caractéristiques des accès à la ROM sont configurées par des paramètres tels que ROMWIDTH et ROMSPEED. ROMWIDTH indique la largeur attendue pour les accès à la ROM, tandis que ROMSPEED intervient dans leurs temporisations. Ces paramètres permettent au contrôleur mémoire d'adapter les cycles de bus aux caractéristiques électriques et temporelles de la mémoire installée.

Sur une console normale, ces paramètres sont configurés par le BIOS pendant l'initialisation. Un logiciel ordinaire ne devrait donc pas supposer qu'il peut modifier arbitrairement la largeur ou accélérer les timings de la ROM. Une temporisation trop agressive peut rendre les lectures instables, tandis qu'une largeur incorrecte peut provoquer des données erronées ou rendre la cartouche inaccessible.

Une cartouche Jaguar peut également contenir une EEPROM série destinée aux sauvegardes. Dans ce cas, le jeu utilise les lignes de contrôle appropriées pour lire et écrire les scores, paramètres ou données de progression. L'EEPROM constitue un composant distinct de la ROM principale et possède son propre protocole ainsi que ses contraintes de programmation.

Des conceptions de cartouches plus élaborées peuvent ajouter de la RAM. Cette mémoire peut servir de zone de travail supplémentaire ou remplir une fonction particulière définie par la cartouche. Une cartouche peut également intégrer un mapper, c'est-à-dire une logique permettant de modifier la manière dont différentes banques ou régions de mémoire sont présentées dans la fenêtre accessible par la console. Un tel mécanisme permet de dépasser les limitations d'une organisation strictement linéaire lorsque le matériel de la cartouche le prévoit.

Le système peut également rencontrer des configurations de type pass-through liées au Jaguar CD. Dans une telle organisation, la cartouche ou le dispositif connecté doit permettre aux signaux nécessaires de continuer vers l'autre matériel concerné. Le connecteur doit donc être compris comme une véritable extension du bus de la console plutôt que comme une simple prise transportant uniquement quelques lignes destinées à lire une ROM.

Physiquement, le connecteur de cartouche expose des lignes d'adresse, de données et de contrôle. Les lignes d'adresse indiquent l'emplacement auquel la console souhaite accéder, les lignes de données transportent les informations lues ou écrites, et les différents signaux de contrôle déterminent notamment le type et le moment des transactions. Une carte connectée à ce bus doit répondre conformément aux timings attendus par la Jaguar.

La cartouche ne doit pas être insérée ou retirée lorsque la console est sous tension. Le connecteur n'est pas conçu comme une interface moderne de type hot-plug. Introduire une carte pendant que les alimentations et les signaux du bus sont actifs peut provoquer des transitions électriques indésirables, des courts-circuits momentanés ou des niveaux logiques incorrects susceptibles d'endommager ou de perturber la console et la cartouche.

Cette précaution est particulièrement importante lors de la conception d'une cartouche homebrew. Une nouvelle carte doit respecter les caractéristiques électriques du connecteur, notamment l'environnement logique et l'alimentation 5 V prévue par le matériel. Les composants employés doivent être compatibles avec les niveaux électriques réellement présents et ne doivent pas imposer au bus des tensions ou des charges qui dépassent ses spécifications.

La conception doit également respecter les timings. Une mémoire ou une logique programmable doit présenter les données suffisamment rapidement après la sélection de l'adresse et maintenir les signaux pendant les intervalles nécessaires. Le respect de la largeur du bus est tout aussi important : le câblage, la logique et l'organisation des ROM doivent correspondre au mode d'accès configuré par la console.

Une carte homebrew doit en outre posséder un découplage électrique approprié. Des condensateurs de découplage placés correctement près des circuits permettent de stabiliser l'alimentation lorsque ceux-ci commutent rapidement. Cette précaution, banale mais essentielle en conception numérique, devient particulièrement importante sur une carte directement reliée au bus d'une console ancienne.

Enfin, la présence d'un programme valide dans la ROM ne garantit pas à elle seule qu'une cartouche démarrera sur une Jaguar utilisant son BIOS original. La conception doit également tenir compte du mécanisme d'authentification associé au chemin de démarrage choisi. Une cartouche commerciale originale, une cartouche homebrew moderne, un environnement de développement ou un BIOS alternatif peuvent utiliser des méthodes différentes pour permettre l'exécution du programme.

La conception d'une cartouche Jaguar exige donc de prendre simultanément en compte la cartographie mémoire, la largeur et les timings du bus, les caractéristiques électriques et le processus de démarrage. La fenêtre ROM1 $800000-$DFFFFF fournit jusqu'à 6 Mio d'espace adressable, même si les cartouches commerciales sont souvent de 2 ou 4 Mio, tandis que le bus ROM est typiquement de 32 bits malgré le chemin DRAM de 64 bits. Des composants supplémentaires comme EEPROM, RAM, mapper ou logique de pass-through peuvent enrichir la cartouche, à condition de respecter le 5 V, les timings, la largeur du bus, le découplage et l'authentification attendus par la configuration de démarrage utilisée.

Formats ROM et chargement

Les logiciels et images de cartouches destinés à la console Atari Jaguar peuvent être rencontrés sous plusieurs formats de fichiers. Des extensions comme .j64, .jag, .rom ou .bin sont couramment utilisées, mais elles ne suffisent pas à déterminer avec certitude l'organisation interne du fichier. Deux fichiers portant des extensions différentes peuvent contenir des données organisées de façon similaire, tandis que deux fichiers portant la même extension peuvent provenir d'outils ou de méthodes de dump différents. Un émulateur ou un utilitaire Jaguar ne doit donc jamais se fier uniquement à l'extension.

Le format .j64 désigne souvent une image linéaire de cartouche en ordre big-endian. Dans cette organisation, les octets sont normalement disposés dans l'ordre attendu par le Motorola 68000, qui utilise lui-même une représentation big-endian. Lorsqu'il s'agit d'une image de cartouche classique, son contenu est généralement présenté dans la fenêtre ROM de la Jaguar à partir de l'adresse $800000. Les adresses suivantes correspondent alors progressivement aux octets suivants du fichier, dans les limites de la cartographie de la cartouche émulée.

Il faut néanmoins éviter de considérer .j64 comme une garantie absolue. L'histoire des outils de copie, des émulateurs et des collections de ROM Jaguar a produit plusieurs variantes. Certaines images peuvent avoir été converties, modifiées ou mal nommées. L'émulateur doit donc vérifier que l'organisation des données est cohérente avant de décider comment les présenter au processeur.

Les fichiers .jag répondent souvent à un besoin différent. Ils peuvent représenter des exécutables Jaguar possédant un en-tête et une adresse de chargement, plutôt qu'une copie brute et complète d'une cartouche. Ces fichiers sont notamment associés à certains environnements de développement, de débogage ou de chargement BJL. L'en-tête peut fournir les informations permettant de déterminer où placer le programme en mémoire et à partir de quelle adresse son exécution doit commencer.

Cette distinction est importante : charger systématiquement un .jag à $800000 comme s'il s'agissait d'une ROM de cartouche peut être incorrect. Lorsque le fichier possède un en-tête exécutable, le chargeur doit interpréter les informations prévues par son format, déterminer l'adresse de chargement et préparer l'exécution conformément au mécanisme BJL, au moniteur de débogage ou à l'environnement auquel le fichier était destiné.

Les extensions .rom et .bin sont encore moins spécifiques. Elles servent généralement à désigner des données binaires ou des images ROM, mais ne définissent pas à elles seules un format Jaguar précis. Un .bin peut être une image linéaire, un programme destiné à être chargé à une adresse particulière ou un fichier produit par un outil de développement. Le même problème existe avec .rom, qui indique essentiellement qu'il s'agit probablement du contenu d'une mémoire morte sans définir son organisation exacte.

On rencontre également des dumps word-swapped. Dans ce cas, les mots ou groupes d'octets du fichier ont été enregistrés dans un ordre différent de celui attendu par la représentation normale utilisée par le 68000. Par exemple, une permutation peut échanger les deux octets à l'intérieur de chaque mot de 16 bits. Un fichier contenant les bonnes données mais dans cet ordre produira évidemment du code et des valeurs incohérents s'il est chargé directement sans conversion.

L'extension seule est donc insuffisante pour décider automatiquement si une image doit être utilisée telle quelle, word-swappée ou interprétée comme un exécutable avec en-tête. Le chargeur doit examiner le contenu et, lorsque cela est possible, utiliser également les métadonnées disponibles sur le fichier et sa provenance.

La détection de l'ordre des octets peut notamment s'appuyer sur des vecteurs, signatures ou structures connues. Des valeurs plausibles à des emplacements attendus, des séquences de code 68000 cohérentes ou des signatures reconnues peuvent permettre de déterminer qu'une interprétation est beaucoup plus vraisemblable qu'une autre. Cette détection doit toutefois être considérée comme une identification du format et non comme une autorisation de modifier arbitrairement le fichier.

Un outil sérieux doit donc préserver l'image originale. Si un fichier nécessite une permutation de mots pour être exécuté, la transformation peut être réalisée dans une copie en mémoire utilisée par l'émulateur, tandis que le fichier source demeure inchangé. Cette séparation permet de conserver exactement les données archivées et évite qu'une détection erronée ne transforme définitivement une ROM correcte.

Il est également préférable de conserver la taille exacte du fichier original. Une image de 2 Mio ne devrait pas être artificiellement transformée en fichier de 4 ou 6 Mio simplement pour remplir toute la fenêtre ROM de la Jaguar. Si l'émulation doit reproduire un miroir, une répétition ou une autre propriété du décodage d'adresse de la cartouche, ce comportement devrait être réalisé par la logique de cartographie mémoire plutôt qu'en modifiant silencieusement le dump.

Pour l'archivage et l'identification, il est utile de conserver également un hash cryptographique du fichier, par exemple SHA-256, ainsi que sa provenance lorsqu'elle est connue. Le hash permet de reconnaître précisément une image et de distinguer deux dumps qui portent le même nom mais ne contiennent pas exactement les mêmes données. La provenance peut indiquer si le fichier provient d'un dump de cartouche, d'un environnement de développement, d'une conversion ancienne ou d'une collection connue.

Cette conservation est particulièrement importante lorsqu'un émulateur applique des transformations au chargement. Il doit être possible de distinguer clairement le hash du fichier original de l'éventuelle représentation transformée utilisée en mémoire. Cela facilite la comparaison avec les bases de données de dumps connus et permet de diagnostiquer les problèmes liés à un mauvais ordre des octets.

Un émulateur Jaguar devrait par conséquent proposer une option de swap explicite. L'utilisateur ou le système de détection peut indiquer que le fichier doit être interprété normalement, avec permutation des mots ou selon un autre format clairement identifié. Une détection automatique peut être proposée, mais son résultat devrait rester identifiable et ne pas masquer complètement la transformation effectuée.

Il faut surtout éviter de « corriger » silencieusement tous les fichiers qui semblent inhabituels. Une image peut être volontairement organisée d'une certaine manière pour un outil de développement, un test matériel ou une recherche sur le comportement de la console. Une correction automatique trop agressive pourrait rendre ce fichier inutilisable ou masquer une erreur réelle que l'utilisateur cherche justement à analyser.

Le chargement des logiciels Jaguar doit ainsi séparer trois questions : quel est le contenu du fichier, dans quel ordre ses données sont-elles stockées et à quelle adresse doivent-elles être présentées ou chargées ? Un .j64 correspond souvent à un dump big-endian linéaire présenté à $800000, tandis qu'un .jag peut être un exécutable avec en-tête et adresse de chargement destiné notamment au BJL ou au débogage. Les .rom, .bin et dumps word-swapped imposent encore davantage de prudence. Pour assurer à la fois compatibilité et fidélité, l'émulateur doit détecter le format à partir du contenu et des métadonnées, préserver l'original, conserver sa taille, son hash et sa provenance, et rendre toute opération de swap explicite plutôt que de modifier silencieusement les images.

Jaguar CD

Le Jaguar CD est une extension matérielle de la console Atari Jaguar destinée principalement à permettre l'utilisation de jeux et de contenus distribués sur CD-ROM. L'unité se branche directement sur le connecteur de cartouche situé sur la console. Elle ne remplace pas l'architecture de la Jaguar : les puces TOM et JERRY, le Motorola 68000 et les autres composants de la console continuent d'assurer leurs fonctions habituelles. Le Jaguar CD ajoute plutôt un nouveau sous-système spécialisé dans la lecture et le traitement des disques optiques.

Le périphérique comporte un lecteur de CD-ROM double vitesse (2×) ainsi que l'électronique nécessaire à son fonctionnement. Cette vitesse doit être comprise dans le contexte des lecteurs CD de l'époque : elle détermine notamment le débit maximal théorique des données, mais les performances réellement observées dépendent aussi des déplacements de la tête, du changement de piste, de la position des secteurs et des opérations réalisées par le contrôleur.

Le Jaguar CD intègre également un contrôleur de CD, de la RAM servant notamment de mémoire tampon, ainsi que des circuits spécialisés comprenant DSP/ASIC. Ces composants prennent en charge différentes fonctions propres au lecteur et permettent de gérer les échanges entre le disque et la console. Le logiciel doit donc considérer le Jaguar CD comme un véritable périphérique matériel possédant ses propres états, commandes et contraintes temporelles, et non comme un simple fichier de grande capacité accessible instantanément.

L'extension prend aussi en charge l'audio CD. Un disque peut ainsi contenir à la fois des pistes de données destinées au programme et des pistes audio pouvant être reproduites comme celles d'un CD audio traditionnel. Cette possibilité permet aux jeux d'utiliser de la musique enregistrée sans devoir nécessairement la stocker et la décoder comme un flux PCM ordinaire dans la RAM principale de la Jaguar.

Une autre fonction caractéristique du Jaguar CD est la Virtual Light Machine (VLM), associée à Jeff Minter. Celle-ci permet de produire des visualisations graphiques réagissant notamment à la musique lors de la lecture de CD audio. Elle constitue une fonction propre au système Jaguar CD et ne doit pas être confondue avec les moteurs graphiques ordinaires utilisés par les jeux.

L'ajout du lecteur introduit des registres matériels et des lignes GPIO supplémentaires. Le logiciel utilise ces ressources pour communiquer avec le sous-système CD, envoyer des commandes, connaître son état et coordonner les transferts. Certaines lignes du connecteur et des GPIO participent donc au dialogue entre la Jaguar de base et son extension. Leur comportement doit être reproduit dans une émulation qui cherche à prendre en charge correctement les logiciels Jaguar CD.

Malgré ces composants supplémentaires, les jeux continuent d'utiliser TOM et JERRY pour les fonctions normales de la console. Le Jaguar CD n'ajoute pas un nouveau système graphique remplaçant le GPU, le Blitter ou l'Object Processor. Les données peuvent être récupérées depuis le disque puis traitées par l'architecture Jaguar habituelle. TOM continue ainsi de gérer le graphisme et la vidéo, tandis que JERRY conserve notamment ses fonctions DSP, audio et d'entrée-sortie.

Le contenu d'un CD Jaguar doit être considéré comme une structure de disque complète, et non simplement comme une succession de fichiers. Le support comporte des secteurs, différentes pistes de données ou audio, une TOC (Table of Contents) décrivant l'organisation des pistes ainsi que des informations participant au mécanisme d'authentification. Certaines caractéristiques physiques ou logiques du disque peuvent donc être significatives pour le démarrage ou pour le fonctionnement du logiciel.

Cette organisation explique pourquoi le choix du format d'image disque est important pour l'émulation et l'archivage. Une simple image ISO représente principalement les données d'un système de fichiers ou d'une piste de données et peut perdre des informations importantes lorsqu'un disque possède plusieurs pistes ou des pistes audio. Elle n'est donc pas toujours suffisante pour représenter fidèlement un disque Jaguar CD original.

Une combinaison BIN/CUE permet généralement de préserver beaucoup mieux l'organisation du support. Le fichier BIN peut contenir les données brutes des secteurs, tandis que le fichier CUE décrit la disposition des pistes, leurs types, leurs positions et leurs transitions. Cette représentation peut également conserver ou décrire correctement les gaps entre certaines pistes, informations qu'une image ISO seule ne représente pas nécessairement.

La distinction devient particulièrement importante pour les jeux utilisant simultanément des pistes de données et des pistes audio. Si l'image disque ne conserve que la partie ISO, les musiques peuvent disparaître complètement. De même, une TOC reconstruite incorrectement ou des positions de pistes différentes de celles du disque original peuvent perturber un logiciel qui dépend de cette organisation.

Les jeux Jaguar CD peuvent également effectuer du streaming de données ou d'audio directement depuis le disque. Ils ne sont donc pas obligés de charger l'intégralité d'une ressource en mémoire avant de commencer à l'utiliser. Cette méthode est particulièrement intéressante compte tenu des seulement 2 Mio de DRAM principale de la Jaguar, mais elle impose de tenir compte des performances et du comportement réel du lecteur.

Un lecteur de CD-ROM mécanique possède en effet des latences qui n'existent pas lorsqu'un émulateur lit directement un fichier depuis un SSD moderne. Le déplacement vers une autre région du disque, la recherche d'une piste et l'arrivée des secteurs prennent du temps. Certains logiciels peuvent dépendre, volontairement ou non, de ces délais. Une émulation fidèle ne devrait donc pas considérer toutes les commandes CD comme instantanées.

Le logiciel peut également rencontrer des erreurs ou états particuliers de lecture. Les mécanismes de commande, les délais de disponibilité et les réponses du contrôleur font partie du comportement observable du Jaguar CD. Pour une émulation précise, il faut reproduire suffisamment ces propriétés afin qu'un jeu utilisant le lecteur de manière inhabituelle ne se comporte pas différemment simplement parce que son image disque est stockée dans un fichier immédiatement accessible.

Le démarrage d'un logiciel Jaguar CD possède également ses propres particularités. Le BIOS du Jaguar CD participe à une procédure de boot distincte de celle d'une cartouche Jaguar ordinaire. Le disque doit être reconnu et les étapes nécessaires au chargement et à l'authentification doivent être réalisées conformément au mécanisme prévu pour le périphérique. Il ne suffit donc pas de monter un ISO et de transférer arbitrairement son premier programme en mémoire.

L'entreposage des sauvegardes peut être complété par l'accessoire Memory Track. Cette extension fournit une mémoire de sauvegarde partagée pouvant être utilisée par différents jeux Jaguar CD. Elle répond notamment au besoin de conserver des progressions, paramètres et autres informations persistantes alors que le CD-ROM lui-même est un support en lecture seule.

Pour un émulateur, la Memory Track doit donc être considérée comme un périphérique persistant distinct du disque. Son contenu doit pouvoir survivre à la fermeture d'un jeu et être retrouvé par d'autres logiciels compatibles, conformément au principe d'une mémoire partagée entre plusieurs titres, plutôt que d'être automatiquement assimilé à une sauvegarde privée incorporée à chaque image CD.

Enfin, la programmation du Jaguar CD nécessite de consulter une documentation CD-ROM spécifique, distincte de la documentation générale consacrée à TOM, JERRY, au GPU, au DSP ou à l'Object Processor. Le lecteur possède ses propres registres, commandes, états, protocoles, timings et mécanismes de démarrage. La seule connaissance de l'architecture de la Jaguar de base n'est donc pas suffisante pour implémenter correctement son extension CD.

Le Jaguar CD doit ainsi être vu comme un sous-système supplémentaire connecté à la Jaguar, comportant un lecteur 2×, son contrôleur, de la RAM tampon, des circuits DSP/ASIC, la lecture audio CD et la Virtual Light Machine. Les jeux continuent à utiliser TOM et JERRY, mais disposent désormais d'un support beaucoup plus volumineux dont les secteurs, pistes, TOC, gaps, authentification et latences peuvent être significatifs. Pour cette raison, une image BIN/CUE est généralement plus appropriée qu'un ISO seul pour préserver un disque complet, tandis qu'une implémentation fidèle doit également tenir compte du BIOS CD, du streaming, des erreurs de lecture et de la mémoire de sauvegarde fournie par la Memory Track.

Memory Track et extensions

La Jaguar et son extension Jaguar CD peuvent être accompagnées de plusieurs périphériques qui étendent les possibilités de la console. Certains sont des accessoires commercialisés à l'époque par Atari ou des fabricants tiers, tandis que d'autres sont des solutions modernes destinées au développement, au homebrew ou au chargement de logiciels. Parmi ces extensions figurent notamment la Memory Track, le JagLink, le Team Tap, la CatBox ainsi que différentes cartouches flash modernes comme la Skunkboard et la GameDrive.

La Memory Track est une cartouche de stockage non volatile principalement destinée aux logiciels du Jaguar CD. Puisqu'un CD-ROM est un support en lecture seule, un jeu exécuté depuis le Jaguar CD ne peut pas enregistrer directement une partie ou des paramètres sur son disque. La Memory Track fournit donc un espace persistant permettant de conserver des informations entre plusieurs sessions de jeu, même après l'extinction de la console.

Il ne faut pas confondre la Memory Track avec une EEPROM qui serait intégrée à la Jaguar elle-même. La console de base ne contient pas simplement une EEPROM générale que tous les jeux pourraient utiliser pour leurs sauvegardes. Certaines cartouches peuvent posséder leur propre EEPROM, tandis que les jeux sur CD peuvent employer la Memory Track lorsqu'elle est présente. Il s'agit donc de mécanismes de stockage distincts.

La Memory Track propose une organisation plus élaborée qu'une simple suite d'octets directement manipulée comme l'EEPROM d'une cartouche. Son utilisation repose sur un système de fichiers ou de slots de sauvegarde, géré avec l'aide du logiciel système associé au Jaguar CD. Les jeux peuvent ainsi créer et retrouver leurs données persistantes dans l'espace de stockage partagé fourni par la cartouche.

Cette organisation signifie également que plusieurs logiciels peuvent utiliser la même Memory Track. Les données doivent être identifiées et organisées de façon à éviter qu'un jeu écrase arbitrairement les sauvegardes d'un autre. Pour un émulateur, il est donc préférable de reproduire le fonctionnement logique de cette mémoire persistante et de son organisation plutôt que de la traiter comme une EEPROM privée automatiquement attachée à chaque image CD.

Le JagLink répond à un besoin complètement différent. Cet accessoire permet de relier plusieurs consoles Jaguar afin que certains jeux compatibles puissent échanger des informations et proposer un fonctionnement en réseau. Les communications utilisent le port série prévu par l'architecture de la console. Chaque Jaguar continue d'exécuter sa propre copie du jeu, tandis que les machines s'échangent les informations nécessaires à la synchronisation de la partie.

Pour un émulateur, reproduire le JagLink ne consiste donc pas simplement à ajouter de nouveaux boutons ou un périphérique local. Il faut représenter une liaison série entre plusieurs instances de la console, avec le comportement et les contraintes temporelles appropriés. Un jeu compatible peut dépendre de l'ordre des données, de leur disponibilité et de la synchronisation entre les machines.

Le Team Tap est pour sa part une extension destinée aux contrôleurs de jeu. Il permet de connecter jusqu'à quatre manettes sur un même port de la Jaguar. Puisque la console possède deux ports de contrôleurs, l'utilisation des Team Tap permet à certains jeux compatibles de prendre en charge davantage de joueurs qu'avec les deux manettes directement raccordées à la machine.

Le Team Tap doit être explicitement pris en charge par le logiciel. Les contrôleurs supplémentaires ne peuvent pas être considérés comme de simples duplications électriques invisibles des deux ports ordinaires. Le jeu doit reconnaître et interroger l'accessoire selon le protocole attendu afin de déterminer l'état des différentes manettes qui lui sont raccordées. Un émulateur prenant en charge les jeux multijoueurs concernés doit donc reproduire cette extension du système d'entrée.

La CatBox constitue une autre catégorie d'extension. Il s'agit d'un périphérique conçu pour fournir à la Jaguar diverses sorties supplémentaires et possibilités de communication. Elle étend ainsi les connexions disponibles autour de la console et peut être utile dans des configurations nécessitant des interfaces qui ne sont pas directement exposées de manière pratique sur une Jaguar standard.

La CatBox ne doit pas être assimilée à un composant interne de TOM ou de JERRY. Il s'agit bien d'une extension externe, dont les fonctions dépendent des signaux accessibles sur la console. Pour une documentation technique ou un émulateur, sa prise en charge doit donc être séparée de celle du matériel de base et activée uniquement lorsqu'une configuration l'exige.

À côté de ces périphériques historiques existent aujourd'hui différentes cartouches flash modernes destinées à la Jaguar. La Skunkboard en est un exemple important. Ce type de matériel permet notamment de transférer et d'exécuter des programmes sans devoir fabriquer une ROM de cartouche définitive pour chaque nouvelle version. Il constitue donc un outil particulièrement pratique pour le développement et l'expérimentation sur le matériel réel.

La GameDrive et d'autres solutions modernes poursuivent des objectifs similaires ou complémentaires. Selon le périphérique, elles peuvent permettre le chargement de logiciels, l'utilisation de mémoire flash, la gestion de certaines sauvegardes, le transfert de programmes depuis un ordinateur ou diverses fonctions destinées au débogage et au développement.

Ces cartouches modernes ne doivent cependant pas être considérées comme possédant toutes une interface commune simplement parce qu'elles se branchent dans le connecteur de cartouche. Chacune peut disposer de son propre protocole de téléversement, de sa propre organisation de stockage, de son propre mécanisme de sauvegarde ou de ses propres fonctions de débogage. Un outil souhaitant les prendre en charge doit donc implémenter le comportement du périphérique concerné plutôt qu'un hypothétique protocole universel de cartouche flash Jaguar.

Il faut ainsi distinguer clairement les différentes catégories d'extensions. La Memory Track fournit du stockage persistant principalement aux jeux Jaguar CD et organise les sauvegardes sous forme de fichiers ou de slots. Le JagLink permet les communications entre consoles par liaison série. Le Team Tap augmente le nombre de contrôleurs disponibles en permettant de connecter quatre manettes à un port. La CatBox ajoute différentes sorties et interfaces de communication.

Enfin, les périphériques modernes comme la Skunkboard, la GameDrive et les autres flash carts prolongent aujourd'hui les possibilités de la machine en proposant leurs propres fonctions de chargement, de sauvegarde, de transfert ou de débogage. Toutes ces extensions reposent sur l'architecture de la Jaguar, mais chacune possède son protocole et son rôle. Une documentation ou une émulation fidèle doit donc les traiter comme des périphériques distincts et optionnels, plutôt que comme des fonctions intégrées d'origine à toutes les consoles Jaguar.

Démarrage d'un programme

Le démarrage d'un programme sur Atari Jaguar commence normalement par l'exécution du BIOS de la console. Après un reset, celui-ci prépare l'environnement matériel nécessaire avant de transférer le contrôle au logiciel de la cartouche. Cette séquence comprend notamment la configuration des registres de contrôle mémoire MEMCON, l'initialisation de la RAM et du système vidéo, ainsi que l'affichage du logo ou de l'animation de démarrage de la Jaguar.

Le BIOS procède également à la vérification de la cartouche. Cette étape fait intervenir le mécanisme d'authentification prévu par Atari et ne doit pas être réduite à un simple test de présence ou à un checksum élémentaire. Lorsque la cartouche est reconnue comme valide, le BIOS poursuit la procédure nécessaire pour atteindre le programme : selon le format et le mécanisme de démarrage concernés, il peut notamment copier ou préparer le code d'entrée, puis lui transférer l'exécution.

Lorsque le programme prend le contrôle, il doit à son tour établir son propre environnement d'exécution. Parmi les premières opérations figurent la préparation de la pile et, lorsque le logiciel l'exige, l'installation ou la préparation des vecteurs d'interruption et d'exception. Ces structures doivent être valides avant d'activer des composants susceptibles de provoquer des interruptions, faute de quoi le processeur pourrait tenter d'exécuter un gestionnaire inexistant ou incorrect.

Le programme doit ensuite placer le GPU de TOM et le DSP de JERRY dans un état connu. Selon leur état initial et l'organisation du logiciel, il peut être nécessaire de les arrêter avant de charger leur code. Le programme peut alors copier les routines appropriées dans leurs RAM locales, préparer les données dont elles ont besoin, fixer leur compteur de programme et initialiser leurs registres de contrôle avant d'autoriser leur exécution.

Cette précaution est particulièrement importante lorsqu'un coprocesseur est susceptible d'être encore actif. Modifier sa mémoire locale ou certains de ses registres pendant qu'il exécute du code peut provoquer des résultats imprévisibles. La séquence correcte consiste donc à s'assurer que le processeur concerné est arrêté, à charger entièrement son programme et son état initial, puis à le relancer seulement lorsque toutes les informations nécessaires sont cohérentes.

Le sous-système vidéo doit lui aussi être configuré. Le programme prépare les timings et le mode d'affichage appropriés, les couleurs ou palettes nécessaires et les structures graphiques utilisées pour construire l'image. Il doit notamment préparer l'Object List que l'Object Processor parcourra pour générer les différentes lignes de l'écran.

Cette Object List doit être entièrement construite avant d'être rendue active. Les descripteurs des Bitmaps, Scaled Bitmaps, Branch Objects et autres objets doivent posséder des valeurs cohérentes, leurs liens doivent conduire aux bons emplacements et les données graphiques auxquelles ils font référence doivent être disponibles. Les contraintes d'alignement et d'ordre des mots propres à l'Object Processor doivent également être respectées.

Il est surtout indispensable que la liste possède déjà un objet STOP valide avant l'activation de l'Object Processor. Le STOP garantit que le parcours de la liste possède une terminaison. Activer l'OP alors que la liste est seulement partiellement construite pourrait lui permettre de suivre un lien non initialisé, de lire des données arbitraires comme des descripteurs ou de parcourir une boucle sans fin, avec des conséquences possibles sur le bus et l'affichage.

L'initialisation doit également couvrir le système audio. Selon l'architecture choisie par le jeu, le programme peut charger un moteur de mixage dans le DSP, préparer ses tables et ses buffers, configurer les horloges et l'interface série audio, puis commencer à fournir les échantillons destinés aux canaux gauche et droit. Comme pour le système graphique, les buffers doivent être prêts avant que le flux temps réel ne commence à les consommer.

Les contrôleurs doivent eux aussi être préparés. Le logiciel configure ou utilise les registres de JERRY nécessaires au balayage de la matrice des manettes, puis met en place sa routine de lecture. Cette dernière doit pouvoir reconstruire l'état de la croix directionnelle, des boutons A/B/C, de Pause, d'Option et du clavier numérique, ainsi que des commandes supplémentaires lorsqu'un périphérique compatible est utilisé.

Une cartouche Jaguar peut exécuter du code directement depuis sa ROM. Il n'est donc pas obligatoire de copier l'intégralité du programme dans la RAM avant de commencer son exécution. Cette possibilité est pratique pour le code général, mais les accès à la ROM ne possèdent pas nécessairement les mêmes caractéristiques de performance que ceux effectués dans les mémoires les plus rapides de la machine.

Pour cette raison, les boucles critiques ou particulièrement performantes sont généralement placées dans une mémoire mieux adaptée. Une routine 68000 fréquemment exécutée peut être copiée en RAM principale, tandis que les calculs destinés au GPU sont avantageusement chargés dans sa RAM locale rapide. De la même manière, les routines audio critiques du DSP doivent autant que possible résider dans sa propre RAM locale.

Lors des copies entre la ROM, la RAM et les mémoires des coprocesseurs, il faut respecter le bon ordre des mots et des octets. Le Motorola 68000 est big-endian, mais certaines structures matérielles de la Jaguar possèdent une disposition particulière lorsqu'elles sont écrites depuis ce processeur. Copier les bonnes données avec un ordre de mots incorrect peut produire un programme invalide, une Object List mal interprétée ou des paramètres matériels erronés.

La Jaguar ne possède pas, dans ce contexte, de caches de données ou d'instructions nécessitant une opération logicielle classique de flush avant qu'un coprocesseur puisse observer les nouvelles valeurs. Après avoir écrit du code ou des données en mémoire, le programme n'a donc pas à effectuer le type de vidage de cache que l'on rencontrerait sur certaines architectures plus modernes.

L'absence de cache ne signifie cependant pas que toutes les modifications mémoire sont automatiquement sûres. Plusieurs processeurs et moteurs matériels peuvent fonctionner simultanément et accéder aux mêmes structures. Le 68000 peut par exemple être en train de modifier une Object List pendant que l'Object Processor la parcourt, ou préparer un buffer pendant qu'un autre moteur le lit.

Les écritures concurrentes doivent donc être explicitement synchronisées. Le programme doit s'assurer qu'une structure est entièrement préparée avant qu'un autre composant commence à l'utiliser, employer des zones ou des tampons alternés lorsque cela est approprié et respecter les contraintes d'atomicité des registres matériels. Cette précaution est d'autant plus importante que certaines écritures 32 bits du 68000 sont réalisées sous la forme de plusieurs cycles de bus et peuvent donc être observées dans un état intermédiaire.

Le démarrage d'un programme Jaguar consiste ainsi à passer progressivement d'une machine initialisée par le BIOS à un environnement entièrement contrôlé par le logiciel. Le BIOS effectue le reset, configure MEMCON, prépare la RAM et la vidéo, affiche le logo, vérifie la cartouche puis lance son point d'entrée. Le programme installe ensuite sa pile et ses vecteurs, prépare le GPU et le DSP, initialise la vidéo, construit une Object List complète terminée par STOP, configure l'audio et les contrôleurs, puis démarre ses différents moteurs.

Une séquence de démarrage robuste doit finalement respecter trois principes : ne jamais rendre actif un composant avant que ses données soient entièrement préparées, conserver le bon ordre des mots lors des copies et synchroniser tous les accès concurrents. L'absence de caches simplifie la cohérence mémoire, mais elle ne supprime ni les problèmes d'atomicité ni la nécessité de coordonner le 68000, le GPU, le DSP, le Blitter et l'Object Processor lorsqu'ils travaillent simultanément.

Initialisation vidéo en assembleur 68000

  1. VMODE   equ $F00028
  2. OLP     equ $F00020
  3. BORD1   equ $F0002A
  4. BG      equ $F00058
  5. VDB     equ $F00046
  6. VDE     equ $F00048
  7.  
  8. InitVideo:
  9.         move.w  #$0000,VMODE           ; garder timebase selon valeur BIOS
  10.         move.w  #$0000,BORD1
  11.         move.w  #$0000,BG
  12.         lea     ObjectList,a0
  13.         move.l  a0,d0
  14.         swap    d0                     ; inverse les deux mots pour OLP
  15.         move.l  d0,OLP
  16.         move.w  #VMODE_CRY16_ON,VMODE
  17.         rts

Employer de préférence la macro `swapw`/OLP du SDK et vérifier le long obtenu dans le listing. Conserver les minuteries BIOS NTSC/PAL plutôt que réécrire HP..VEE avec une table d'une autre région.

Exemple minimal d'Object List

Avec les macros RMAC :

  1.         .objproc
  2.         .phrase
  3. ObjectList:
  4.         branch  StopObj,VC_LT,VIDEOBEGIN
  5.         branch  StopObj,VC_GT,VIDEOEND
  6.         bitmap  Screen,0,VIDEOBEGIN,40,40,240,3,0,NOTRANS,0,1
  7. StopObj:
  8.         stop
  9.         .68000

Pour 320 pixels à 8 bpp, une ligne vaut 320 octets = 40 phrases. Les paramètres exactes des macros dépendent de RMAC. Après chaque trame, restaurer DATA/HEIGHT du bitmap ou garder une copie modèle et recopier les phrases modifiées.

Lancement d'un programme GPU

  1. G_RAM   equ $F03000
  2. G_FLAGS equ $F02100
  3. G_PC    equ $F02110
  4. G_CTRL  equ $F02114
  5.  
  6. StartGPU:
  7.         bclr    #0,G_CTRL              ; RUN=0 selon largeur/bit documente
  8. .wait:  btst    #0,G_CTRL
  9.         bne.s   .wait
  10.         lea     GPUCode,a0
  11.         lea     G_RAM,a1
  12.         move.w  #(GPUCodeEnd-GPUCode)/4-1,d0
  13. .copy:  move.l  (a0)+,(a1)+
  14.         dbra    d0,.copy
  15.         move.l  #G_RAM,G_PC
  16.         move.l  #GPU_FLAGS_INIT,G_FLAGS
  17.         bset    #0,G_CTRL
  18.         rts

Les registres Tom sont souvent accédés avec largeur imposée; `bclr/bset` sur mémoire peut provoquer read-modify-write indésirable. En production, lire/masquer un long puis écrire selon séquence officielle.

Exemple de boucle GPU

Syntaxe RISC RMAC :

  1.         .gpu
  2.         .org    G_RAM
  3. GPU_ENTRY:
  4.         movei   #CommandPtr,r14
  5.         load    (r14),r0
  6.         cmpq    #0,r0
  7.         jr      eq,GPU_IDLE
  8.         nop                             ; slot/delai selon pipeline
  9.         ; traiter commande ou preparer Blitter
  10.         moveq   #0,r1
  11.         store   r1,(r14)                ; acquittement
  12. GPU_IDLE:
  13.         jump    t,(r31)                 ; convention boucle/retour a definir
  14.         nop

Un vrai noyau initialise r31 et vecteurs, place NOP/hazards selon manuel et emploie une boite aux lettres alignée. `jump t` est condition toujours vraie dans plusieurs syntaxes; vérifier RMAC.

Lancement d'un programme DSP

  1. D_RAM   equ $F1B000
  2. D_FLAGS equ $F1A100
  3. D_PC    equ $F1A110
  4. D_CTRL  equ $F1A114

Procédure identique au GPU : arrêter, attendre, copier code par longs dans RAM locale, initialiser tampons/sériel, fixer PC/FLAGS, lancer. DSP et GPU ont mêmes offsets conceptuels mais bases différentes; ne pas écrire Tom en pensant Jerry.

Le 68000 publie commandes audio dans DRAM ou DSP RAM. Pour un flux continu, double tampon avec index producteur/consommateur et compteur, pas un simple flag qui peut perdre deux commandes.

Exemple sonore

Pseudo-RISC DSP :

  1. AudioLoop:
  2.         load    (r14),r0               ; sample gauche
  3.         addq    #4,r14
  4.         load    (r15),r1               ; sample droite
  5.         addq    #4,r15
  6. WaitSerial:
  7.         loadw   (r20),r2               ; statut serie
  8.         btst    #READY_BIT,r2
  9.         jr      eq,WaitSerial
  10.         nop
  11.         storew  r0,(r21)               ; DAC gauche/droite selon protocole
  12.         storew  r1,(r21)
  13.         jr      t,AudioLoop
  14.         nop

Les adresses SCLK/SMODE/TX et le sens stéréo doivent être pris dans `jerry.inc`. La boucle doit gérer fin, interpolation, saturation et interruption sans lire au-delà du tampon.

Exemple de copie Blitter

Pseudo-68000 :

  1.         bsr     WaitBlitter
  2.         move.l  #Source,A1_BASE
  3.         move.l  #A1_FLAGS_VALUE,A1_FLAGS
  4.         move.l  #Destination,A2_BASE
  5.         move.l  #A2_FLAGS_VALUE,A2_FLAGS
  6.         move.l  #(HEIGHT<<16)|WIDTH,B_COUNT
  7.         move.l  #CMD_SRC_COPY,B_CMD
  8.  
  9. WaitBlitter:
  10.         move.l  B_CMD,d0
  11.         btst    #BLIT_BUSY_BIT,d0
  12.         bne.s   WaitBlitter
  13.         rts

Selon silicium, busy se lit dans commande/contrôle et les registres ont ordre d'écriture recommande. Les constantes doivent préciser pixel/phrase, largeur, pitch, incrément et LFU. Tester alignement et chevauchement source/destination.

Lecture d'un contrôleur

  1. JOYSTICK equ $F14000
  2. JOYBUTS  equ $F14002
  3.  
  4. ReadPad1:
  5.         lea     ScanRows(pc),a0
  6.         lea     PadRaw,a1
  7.         moveq   #3,d0
  8. .row:  move.w  (a0)+,JOYSTICK          ; selection d'une ligne active
  9.         nop
  10.         move.w  JOYSTICK,d1
  11.         move.w  JOYBUTS,d2
  12.         move.w  d1,(a1)+
  13.         move.w  d2,(a1)+
  14.         dbra    d0,.row
  15.         rts
  16.  
  17. ScanRows:
  18.         dc.w ROW0,ROW1,ROW2,ROW3
  19. PadRaw: ds.w 8

Les masques ROW et tables de décodage viennent du manuel/SDK. Ne pas maintenir deux lignes incompatibles et rendre les lignes inactives après balayage.

Gestion des interruptions

La gestion des interruptions constitue un élément important de la programmation de la console Atari Jaguar, car plusieurs circuits matériels peuvent demander l'attention du Motorola 68000. Les interruptions permettent au processeur de réagir à des événements sans devoir interroger continuellement tous les périphériques. Parmi les sources gérées par TOM figurent notamment les événements vidéo, le GPU, l'Object Processor, les minuteries et le Blitter. Un gestionnaire d'interruption doit identifier précisément la ou les sources actives, effectuer le traitement nécessaire, puis les acquitter correctement avant de rendre le contrôle au programme interrompu.

Lorsqu'une interruption atteint le 68000, le gestionnaire doit commencer par préserver le contexte dont il aura réellement besoin. Une stratégie efficace consiste à sauvegarder uniquement les registres que le descripteur va modifier, plutôt que de sauvegarder systématiquement tous les registres du processeur. Cette approche réduit le nombre d'accès à la pile et donc le temps passé dans le gestionnaire. Elle exige cependant une discipline stricte : tout registre modifié par le descripteur doit être restauré avant le retour.

Le gestionnaire peut ensuite lire le registre INT1 de TOM afin de déterminer quelles sources d'interruption sont actuellement signalées. Plusieurs événements peuvent être en attente simultanément ; il ne faut donc pas nécessairement considérer l'interruption comme provenant d'une seule source. Le descripteur doit examiner les bits appropriés et traiter successivement les événements correspondant à la vidéo, au GPU, à l'Object Processor, aux minuteries ou au Blitter, selon les sources qui sont réellement actives et activées.

Le traitement doit respecter une distinction importante entre l'acquittement de la source dans son propre périphérique et l'effacement de son état dans le contrôleur d'interruptions de TOM. Lorsqu'un périphérique possède son propre indicateur ou mécanisme d'acquittement, le gestionnaire doit d'abord effectuer l'opération prévue dans le bloc matériel concerné. Il peut ensuite écrire les bits de clear appropriés dans TOM afin d'effacer le latch correspondant dans le contrôleur d'interruptions.

Cet ordre est important. Effacer uniquement le bit visible dans TOM sans supprimer la condition à l'origine de la demande peut laisser le périphérique dans un état où il continue à réclamer une interruption. Inversement, traiter le périphérique sans effacer correctement le latch de TOM peut laisser l'interruption signalée au 68000. Le gestionnaire doit donc respecter la procédure d'acquittement propre à chaque source puis effectuer le clear correspondant dans TOM.

Une source qui n'est pas correctement effacée peut réinterrompre immédiatement le processeur. Après le retour du gestionnaire, le 68000 peut alors recevoir de nouveau exactement la même interruption, parfois avant même que le programme principal ait exécuté une instruction utile. Dans le pire cas, le système peut rester pratiquement enfermé dans une succession de handlers d'interruption. Une interruption qui se répète anormalement doit donc faire rechercher en priorité un problème d'acquittement ou de clear.

Après avoir traité toutes les sources pertinentes, le gestionnaire doit restaurer les registres qu'il avait sauvegardés. Le retour ne s'effectue pas comme celui d'un sous-programme ordinaire : le Motorola 68000 utilise l'instruction RTE (Return from Exception). Celle-ci restaure l'état approprié sauvegardé lors de l'exception, notamment les informations nécessaires pour reprendre correctement l'exécution du programme interrompu.

Parmi les événements vidéo, la période de VBlank ou l'interruption vidéo VI constitue un moment particulièrement utile pour synchroniser les différentes parties du moteur. Pendant cette période, le programme peut effectuer des opérations qui doivent être coordonnées avec le changement de trame, notamment la préparation des structures que l'Object Processor utilisera pour l'image suivante.

Une tâche importante consiste à restaurer l'Object List. L'Object Processor modifie lui-même certains champs de ses descripteurs pendant leur consommation : DATA avance, HEIGHT diminue et, pour un Scaled Bitmap, REMAINDER évolue également. Si les mêmes objets doivent être réutilisés à la trame suivante, ces champs doivent être remis dans l'état prévu, tandis que les positions, liens ou autres paramètres d'animation peuvent être actualisés.

La synchronisation verticale constitue également un moment naturel pour permuter les tampons. Dans un moteur utilisant un double framebuffer, le tampon qui vient d'être rendu peut devenir celui présenté à l'Object Processor, tandis que l'ancien tampon affiché devient disponible pour la construction de l'image suivante. Cette permutation doit être effectuée de manière cohérente afin que le matériel ne commence pas à lire un pointeur ou une structure partiellement mis à jour.

Le VBlank ou VI peut également servir à publier de nouvelles commandes au GPU et au DSP. Le 68000 peut préparer les paramètres nécessaires à la prochaine trame, signaler au GPU qu'une nouvelle série de calculs ou de commandes graphiques est disponible et communiquer au DSP les informations dont son traitement a besoin. Le mot « publier » implique ici une synchronisation : les données doivent être complètement écrites avant que le coprocesseur soit averti qu'il peut les consommer.

Le Stop Object de l'Object Processor peut fournir un autre point de synchronisation. Un objet STOP peut être configuré pour signaler que l'OP a atteint la fin prévue de son parcours. Le programme peut utiliser cet événement comme indication de fin de traitement de l'Object List, ce qui permet de coordonner certaines modifications avec un moment où l'OP a terminé la partie concernée de son travail.

Cette synchronisation est indispensable parce qu'il ne faut jamais modifier sans précaution une phrase de 64 bits que l'Object Processor est susceptible de lire simultanément. Le 68000 ne peut pas nécessairement remplacer une phrase complète de manière atomique puisqu'il utilise un bus externe de 16 bits. L'OP pourrait donc observer une structure dont seulement une partie a été mise à jour et interpréter un mélange entre l'ancienne et la nouvelle valeur.

Lorsqu'une structure doit être modifiée pendant que l'affichage fonctionne, une solution consiste à utiliser un double buffering. Le programme prépare une copie inactive de l'Object List ou de la partie concernée, puis bascule vers cette version seulement lorsqu'elle est entièrement cohérente. L'Object Processor continue ainsi de lire une structure stable pendant que le processeur construit la suivante.

Une autre technique consiste à utiliser une branche de clip afin d'empêcher temporairement l'Object Processor d'atteindre la région de la liste que le programme souhaite modifier. Les Branch Objects peuvent détourner le parcours pendant les lignes ou périodes où certains objets ne doivent pas être consommés. Le logiciel peut alors organiser ses modifications de manière à ce que l'OP ne lise jamais un descripteur pendant sa reconstruction.

Une gestion robuste des interruptions Jaguar doit donc coordonner à la fois le 68000 et les moteurs matériels fonctionnant en parallèle. Le descripteur sauvegarde les registres utilisés, consulte INT1, traite les sources vidéo/GPU/OP/timer/Blitter, acquitte chaque périphérique, efface les bits correspondants dans TOM, restaure le contexte puis termine par RTE. Les interruptions de VBlank/VI peuvent servir à restaurer l'Object List, permuter les tampons et publier les commandes des coprocesseurs, tandis que le Stop Object fournit un point supplémentaire de synchronisation. Enfin, toute modification de données simultanément accessibles à l'Object Processor doit être protégée par une stratégie telle que le double buffering ou les branches de clip, afin que l'OP ne voie jamais une phrase partiellement modifiée.

Rendu 2D

Le rendu 2D sur la console Atari Jaguar repose principalement sur la coopération entre l'Object Processor (OP) et le Blitter, tous deux intégrés à la puce TOM. L'Object Processor est particulièrement adapté à l'affichage de fonds, sprites, couches graphiques et objets redimensionnés, tandis que le Blitter peut effectuer rapidement des opérations de dessin et de modification de surfaces. Cette organisation permet de réaliser un moteur 2D sans demander au Motorola 68000 de dessiner individuellement tous les pixels.

Une particularité importante de l'Object Processor est qu'il peut construire l'image sans nécessiter de framebuffer complet. À chaque ligne vidéo, l'OP parcourt son Object List, détermine quels objets sont actifs, récupère leurs pixels en DRAM et les compose directement dans le line buffer. Un jeu 2D peut donc représenter son écran comme une succession de fonds, sprites et autres couches indépendantes plutôt que de rendre préalablement toute la scène dans une grande image en mémoire.

Cette méthode est particulièrement intéressante pour les sprites. Chaque élément graphique peut être décrit comme un Bitmap Object possédant notamment sa propre adresse DATA, ses coordonnées XPOS et YPOS, sa profondeur de couleur et ses dimensions. Plusieurs objets peuvent être superposés dans l'Object List afin de construire progressivement la ligne. La transparence permet alors aux parties invisibles d'un sprite de laisser apparaître les objets ou le fond déjà présents dans le line buffer.

Les couches graphiques peuvent être organisées selon le même principe. Un décor, une couche intermédiaire et des sprites situés au premier plan peuvent être représentés par des objets différents. Leur ordre dans l'Object List participe à leur ordre de composition. Cette approche convient naturellement aux jeux utilisant plusieurs plans de décor ou de nombreux éléments graphiques indépendants.

L'Object Processor possède également la capacité d'afficher des Scaled Bitmaps, ce qui permet d'obtenir du zoom matériel. Le programme peut modifier les facteurs HSCALE et VSCALE afin d'agrandir ou de réduire un objet sans devoir créer en mémoire une nouvelle copie de l'image à chaque taille. Le redimensionnement reste celui de l'OP, fondé sur la répétition ou le saut de pixels et de lignes plutôt que sur un filtrage bilinéaire.

Pour effectuer un scrolling, le programme peut notamment ajuster le champ DATA afin de déplacer le point de départ dans l'image source. Un déplacement horizontal peut également nécessiter une modification de XPOS et une gestion correcte du premier pixel et de l'organisation des phrases. L'idée générale consiste à modifier l'adresse et la position à partir desquelles l'Object Processor commence à récupérer les données plutôt qu'à recopier tout le décor à une nouvelle position en mémoire.

Le padding est particulièrement important dans ce contexte. L'Object Processor effectue ses lectures selon l'organisation en phrases de 64 bits et peut avoir besoin d'accéder à une phrase complète même lorsque seule une partie de ses pixels est visible. Les lignes graphiques doivent donc posséder suffisamment de données de remplissage et respecter les alignements nécessaires. Un scrolling qui déplace DATA vers une nouvelle position doit continuer à garantir que les lectures effectuées par l'OP restent valides.

L'animation d'un sprite peut elle aussi être réalisée avec très peu de modifications. Si les différentes images d'une animation sont stockées séparément ou à des adresses connues, le programme peut simplement changer DATA pour faire pointer l'objet vers la nouvelle frame. Les autres caractéristiques du sprite - position, profondeur, palette ou dimensions - peuvent rester identiques lorsqu'elles ne changent pas d'une image à l'autre.

Une autre stratégie consiste à organiser plusieurs images d'animation dans une bande de frames en mémoire et à exploiter la progression de l'Object Processor dans les données. En contrôlant correctement l'adresse de départ et la hauteur consommée, il est possible de faire parcourir à l'OP différentes portions de cette bande. Cette technique doit être soigneusement synchronisée avec le comportement de DATA et de HEIGHT, puisque l'Object Processor modifie ces champs pendant son traitement.

Le Blitter complète ces possibilités lorsqu'il est préférable de modifier réellement une surface graphique. Il peut être utilisé pour dessiner des tuiles, du texte, des particules ou d'autres éléments dans un tampon en DRAM. Dans un moteur basé sur une tilemap, par exemple, le programme peut demander au Blitter d'assembler différentes tuiles dans une surface que l'Object Processor affichera ensuite.

Le Blitter est également capable d'effectuer des opérations RMW (Read-Modify-Write). Dans ce mode, il ne se contente pas d'écrire une nouvelle valeur : il peut lire le contenu existant d'une destination, effectuer l'opération configurée puis réécrire le résultat. Ce mécanisme permet de réaliser différentes formes de composition, d'opérations logiques et d'effets graphiques sur des surfaces déjà présentes en mémoire.

Pour les petits objets, les formats utilisant la CLUT sont particulièrement intéressants. Des images à 1, 2, 4 ou 8 bits par pixel nécessitent beaucoup moins de données qu'un objet stocké directement en 16 bits par pixel. Le pixel contient alors un indice qui est converti en couleur physique par l'intermédiaire de la palette. Cette représentation peut réduire sensiblement la quantité de données que l'Object Processor doit récupérer en DRAM.

La réduction de la taille des pixels permet donc d'économiser de la bande passante mémoire, ressource importante sur Jaguar puisque la DRAM est partagée entre plusieurs unités. Pour de nombreux petits sprites ou éléments d'interface ne nécessitant qu'un nombre limité de couleurs, les formats CLUT de 1 à 8 bpp peuvent être plus efficaces que l'utilisation systématique de Bitmaps directs de 16 bits.

Le comportement du bus peut également être influencé par l'option RELEASE de l'objet. Lorsqu'elle est utilisée, l'Object Processor peut rendre le bus entre certains fetches au lieu de le conserver continuellement. Cela permet aux autres unités de la Jaguar d'obtenir plus facilement des créneaux d'accès à la DRAM entre les lectures nécessaires à l'objet.

Cette stratégie peut être avantageuse pour de petits objets indexés, dont les données sont relativement compactes et pour lesquels monopoliser le bus n'apporte pas nécessairement un gain important. Libérer le bus entre les accès peut réduire la contention avec le GPU, le DSP, le Blitter ou le 68000.

À l'inverse, pour de grands objets continus en 16 bpp, conserver le bus pendant une séquence de lectures peut être avantageux. Les données sont alors récupérées de manière régulière et peuvent bénéficier de l'organisation en page mode de la DRAM. Une libération trop fréquente du bus pourrait interrompre cette séquence et conduire à davantage de changements ou de réouvertures de pages, avec les pénalités correspondantes.

Le choix entre conserver et relâcher le bus doit donc tenir compte de la nature des données. Les petits objets CLUT de 1 à 8 bpp peuvent économiser simultanément de la mémoire et de la bande passante, et RELEASE peut améliorer le partage du bus entre leurs fetches. Les objets 16 bpp continus, en revanche, peuvent bénéficier d'accès soutenus permettant de rester dans une organisation mémoire favorable et d'éviter des pénalités de changement de page.

Le rendu 2D de la Jaguar repose ainsi sur une approche très différente d'un moteur qui dessinerait obligatoirement toute l'image dans un framebuffer. L'Object Processor peut composer directement fonds, sprites, couches et zooms ligne par ligne, tandis que le Blitter prend en charge les opérations nécessitant de dessiner ou de transformer réellement des surfaces. En combinant correctement DATA, XPOS, le padding, les formats CLUT, RELEASE et l'organisation de la DRAM, un moteur 2D peut réduire considérablement les copies de pixels et exploiter efficacement la bande passante disponible.

Rendu 3D

Le rendu 3D sur Atari Jaguar repose sur un pipeline principalement logiciel, réparti entre plusieurs unités de la console. Contrairement aux processeurs graphiques modernes, la Jaguar ne possède pas de moteur matériel fixe capable de recevoir directement des triangles et de les rasteriser automatiquement. Le programme doit donc construire lui-même les différentes étapes du pipeline 3D et répartir le travail entre le GPU, le Blitter, l'Object Processor et, dans une moindre mesure, le Motorola 68000.

Le GPU de TOM constitue normalement le principal processeur de calcul géométrique. Il peut prendre les sommets décrivant les objets de la scène et leur appliquer les transformations nécessaires pour passer des coordonnées de l'objet aux coordonnées utilisées pour l'affichage. Les opérations de transformation comprennent notamment les calculs associés à la position et à l'orientation des objets et de la caméra.

Après ces transformations, le GPU peut effectuer les opérations de soustraction et de comparaison nécessaires aux calculs géométriques, puis procéder au clipping des sommets ou des primitives. Le clipping permet d'éliminer les parties situées complètement hors de la zone visible et de découper celles qui traversent les limites de la vue. Cette étape évite de transmettre au rasteriseur des zones qui ne pourront de toute façon pas apparaître à l'écran.

Le GPU calcule ensuite les bords des polygones. Pour un triangle, par exemple, il peut déterminer les intersections de ses arêtes avec les différentes lignes horizontales de l'image. À partir de ces informations, le programme construit des spans, c'est-à-dire des segments horizontaux correspondant aux pixels qui doivent être tracés sur une ligne donnée.

Le Blitter prend alors en charge une grande partie de la rasterisation. Au lieu de lui demander de dessiner directement un « triangle » - primitive qu'il ne connaît pas en tant que telle - le GPU configure le Blitter pour tracer successivement les spans calculés. Chaque span possède une position de départ, une longueur et éventuellement des valeurs initiales et des incréments destinés aux coordonnées de texture, aux couleurs ou à la profondeur.

Le Blitter peut ainsi remplir un framebuffer situé dans la DRAM principale. Selon le moteur utilisé, les spans peuvent être de simples surfaces colorées ou employer le texture mapping, l'ombrage Gouraud et le Z-buffer. Les générateurs d'adresses et les incréments fractionnaires du Blitter sont particulièrement utiles pour faire évoluer les paramètres d'un pixel au suivant.

Pour un rendu Gouraud, les valeurs de couleur ou d'intensité sont interpolées progressivement le long du span. Le GPU calcule les valeurs de départ et les variations nécessaires, puis le Blitter applique les incréments pendant le tracé. Cette méthode permet de produire des surfaces dont l'éclairage varie progressivement entre les sommets plutôt que d'utiliser une couleur uniforme pour l'ensemble du polygone.

Le Z-buffer permet quant à lui de déterminer quelles surfaces sont visibles lorsque plusieurs polygones se superposent. Une valeur de profondeur est associée à chaque pixel ou position correspondante. Lors du dessin, le Blitter compare la profondeur du nouveau fragment avec celle déjà enregistrée et peut inhiber l'écriture de la couleur lorsque le fragment est masqué, tout en gérant l'écriture du Z conformément au mode configuré.

Une fois l'image construite dans le framebuffer, l'Object Processor peut l'afficher comme un Bitmap Object. L'OP n'a donc pas besoin de connaître la géométrie 3D qui a servi à produire l'image : pour lui, le résultat final est simplement une surface graphique située en mémoire qu'il doit transférer vers les line buffers pendant le balayage vidéo.

Cette organisation permet de séparer clairement les tâches : le GPU traite la géométrie et prépare les spans, le Blitter rasterise les spans dans le framebuffer, puis l'Object Processor affiche le framebuffer. Ce pipeline n'est toutefois pas imposé par le matériel ; un programme peut l'adapter, le simplifier ou répartir différemment certaines opérations en fonction de ses besoins.

L'utilisation d'un double buffering est particulièrement importante pour ce type de rendu. Un framebuffer est affiché par l'Object Processor pendant que le GPU et le Blitter construisent l'image suivante dans un second framebuffer. Lorsque la nouvelle image est terminée, les rôles des deux buffers peuvent être échangés à un moment synchronisé avec la vidéo.

Cette technique permet d'éviter le tearing, c'est-à-dire l'affichage simultané de portions appartenant à deux états différents de l'image. Sans double buffering, le Blitter pourrait modifier un framebuffer au moment même où l'Object Processor est en train de le lire pour l'affichage, produisant une coupure visible entre l'ancienne et la nouvelle image.

Le texture mapping en perspective correcte constitue une difficulté supplémentaire. Une simple interpolation linéaire des coordonnées de texture U et V dans l'espace écran ne reproduit pas correctement la perspective sur un grand polygone. Les coordonnées doivent tenir compte de la profondeur, ce qui nécessite des opérations supplémentaires, notamment des divisions ou des interpolations basées sur des valeurs corrigées en fonction de la profondeur.

Sur Jaguar, une solution consiste à effectuer les divisions et à recalculer les incréments pour chaque span ou pour certaines portions de celui-ci. Le GPU peut déterminer les coordonnées appropriées au début et à la fin du segment, puis fournir au Blitter les valeurs et incréments nécessaires. Cette méthode améliore la correction perspective mais augmente évidemment la quantité de calculs.

Une autre approche consiste à utiliser la subdivision. Un grand polygone ou un long span est découpé en plusieurs portions plus petites, sur lesquelles l'approximation linéaire devient moins visible. Le programme échange alors davantage de travail géométrique et de commandes de Blitter contre une meilleure approximation de la perspective. Le choix dépend du compromis recherché entre précision et performances.

L'organisation des textures en mémoire influence fortement les performances. Comme le Blitter travaille efficacement avec les phrases de 64 bits de la Jaguar, les textures doivent autant que possible être alignées sur les limites de phrase et organisées de manière à favoriser des accès séquentiels. Un mauvais alignement peut augmenter le nombre d'accès nécessaires et provoquer davantage de changements de page DRAM.

Les données fréquemment utilisées et suffisamment petites peuvent également être placées dans la RAM locale du GPU ou dans une forme de cache logiciel géré par le programme. La Jaguar ne fournit pas ici un cache de textures matériel comparable à celui des GPU modernes : c'est le programme qui peut conserver localement certaines petites tables ou portions de données critiques afin de réduire les accès répétés à la DRAM.

Cette optimisation est importante parce que la DRAM est partagée par le GPU, le Blitter, l'Object Processor, le 68000 et d'autres unités. Réduire les lectures inutiles de textures permet donc non seulement d'accélérer le rasteriseur, mais aussi de diminuer la contention qui pourrait ralentir les autres composants de la console.

L'entreposage du Z-buffer constitue lui aussi une part importante du coût mémoire. Un moteur peut utiliser des valeurs de profondeur sur 16 bits, ce qui fournit un compromis entre précision et consommation de RAM. Les données de profondeur et de couleur peuvent être entrelacées en mémoire, notamment afin de conserver une organisation favorable aux accès DRAM et de limiter les changements de page pendant certaines opérations du Blitter.

Le Motorola 68000 conserve malgré tout un rôle important dans un jeu 3D. Il peut gérer la logique de la scène, les objets, les scripts, les contrôles, l'intelligence artificielle, les collisions de haut niveau et l'orchestration générale des différents processeurs. Il peut également préparer les informations nécessaires aux tâches qui seront confiées au GPU.

En revanche, le 68000 ne doit généralement pas rasteriser l'image pixel par pixel. Son bus externe de 16 bits et sa vitesse le rendent beaucoup moins approprié que le Blitter pour ce travail intensif. Utiliser le 68000 pour calculer et écrire individuellement chaque pixel gaspillerait une grande partie du potentiel de l'architecture parallèle de la Jaguar.

Un moteur 3D efficace sur Jaguar doit donc exploiter les points forts de chaque composant : le 68000 organise la scène et l'IA, le GPU transforme et clippe les sommets puis construit les bords et les spans, le Blitter effectue le texture mapping, le Gouraud et les opérations de Z-buffer dans un framebuffer, et l'Object Processor présente finalement ce framebuffer à l'écran. Le double buffering évite le tearing, tandis que l'alignement des textures, l'utilisation judicieuse de la RAM locale et l'organisation du Z-buffer permettent de réduire la pression exercée sur la DRAM.

La Jaguar peut ainsi produire des scènes 3D complexes, mais cette capacité provient de la programmation coordonnée de plusieurs moteurs, et non d'un rasteriseur de triangles matériel intégré. Les performances dépendent directement de la manière dont le programme construit ses spans, gère la correction perspective, organise les textures et répartit le travail entre GPU, Blitter, OP et 68000.

Synchronisation et partage de données

L'architecture de l'Atari Jaguar repose fortement sur le travail simultané de plusieurs unités : le Motorola 68000, le GPU, le DSP, le Blitter et l'Object Processor peuvent tous manipuler des données partagées ou accéder à la DRAM. Cette organisation permet d'obtenir de bonnes performances, mais elle impose une gestion rigoureuse de la synchronisation. Deux composants ne doivent pas modifier ou interpréter simultanément une structure lorsque celle-ci se trouve dans un état intermédiaire.

La Jaguar ne possède pas de caches classiques nécessitant un protocole de cohérence de cache entre ses processeurs. Il n'est donc généralement pas nécessaire d'effectuer les opérations de cache flush ou d'invalidation que l'on rencontre sur certaines architectures multiprocesseurs modernes. Cela ne signifie toutefois pas que tous les échanges de données sont automatiquement sûrs. Les problèmes d'ordre des écritures, d'atomicité et de concurrence entre les différents maîtres du bus restent essentiels.

Le Motorola 68000 constitue un exemple particulièrement important. Même si son jeu d'instructions permet d'effectuer une opération sur un long de 32 bits, son bus externe sur Jaguar est de 16 bits. Une écriture de 32 bits est donc réalisée sous la forme de plusieurs transferts de mots de 16 bits. Entre ces transferts, un autre composant peut éventuellement obtenir l'accès au bus.

Le GPU ou un autre moteur matériel peut ainsi observer une valeur intermédiaire. Supposons qu'un mot long de 32 bits passe d'une ancienne valeur à une nouvelle : après l'écriture du premier mot de 16 bits mais avant celle du second, la mémoire contient temporairement une combinaison d'une moitié nouvelle et d'une moitié ancienne. Si le GPU lit précisément à cet instant, il obtient une valeur qui n'a jamais été volontairement publiée par le programme.

Ce problème est particulièrement dangereux pour les pointeurs, compteurs, adresses, commandes et descripteurs matériels. Une valeur intermédiaire utilisée comme adresse peut conduire un coprocesseur vers une zone complètement incorrecte de la mémoire. Une structure partagée doit donc être organisée de façon à ce que le consommateur ne commence jamais à la lire avant que le producteur ait terminé toutes ses modifications.

Une technique courante consiste à utiliser un mécanisme de publication par drapeau (flag). Le producteur commence par écrire toutes les données composant la structure partagée : paramètres, adresses, compteurs, commandes et autres valeurs nécessaires. Tant que cette préparation n'est pas terminée, le consommateur considère la structure comme indisponible.

Une fois toutes les données préparées, le producteur écrit en dernier un flag indiquant que la structure est prête. Ce flag doit utiliser une taille et un chemin d'accès pour lesquels l'écriture est atomique du point de vue du maître qui le consomme. Selon le composant concerné, il peut s'agir d'un indicateur de 16 ou 32 bits, à condition que son écriture ne puisse pas être observée partiellement par le consommateur.

L'ordre est essentiel : les données d'abord, le flag ensuite. Si le flag était écrit avant la fin de la structure, le consommateur pourrait détecter « prêt » et commencer immédiatement à lire des champs encore incomplets. Le flag représente donc non seulement un état logique, mais aussi la frontière indiquant que toutes les écritures nécessaires ont déjà été effectuées.

Lorsque le consommateur détecte le flag, il peut traiter la structure. Une fois le travail terminé ou la commande récupérée, il efface le flag afin d'indiquer au producteur que l'emplacement peut être réutilisé. Ce mécanisme forme un protocole simple de type producteur-consommateur et évite qu'une nouvelle commande écrase la précédente avant qu'elle ait été prise en compte.

La synchronisation concerne également le code exécuté par le GPU et le DSP. Avant de modifier le programme contenu dans la RAM locale d'un processeur RISC, celui-ci doit être arrêté. Réécrire des instructions pendant qu'il les exécute pourrait lui faire lire un mélange entre ancien et nouveau code ou modifier une instruction située dans son pipeline.

La séquence sûre consiste donc à demander l'arrêt du processeur RISC, à vérifier qu'il est effectivement arrêté, puis à modifier ou remplacer son code et les données critiques associées. Le compteur de programme et les registres nécessaires peuvent ensuite être réinitialisés avant de réactiver RUN. Cette règle s'applique aussi bien au GPU de TOM qu'au DSP de JERRY.

Le Blitter impose une contrainte similaire. Une fois qu'une opération a été lancée, ses registres décrivent le travail en cours. Le 68000 ou le GPU ne doit pas simplement les reprogrammer comme si le moteur était déjà disponible. Il faut attendre que le Blitter ait terminé l'opération précédente, généralement en contrôlant son état busy, avant de modifier les registres destinés à la commande suivante.

Sans cette attente, certains paramètres d'une nouvelle opération pourraient être introduits pendant que le Blitter utilise encore les anciens. Le résultat pourrait être une copie incorrecte, un dessin corrompu, une mauvaise adresse mémoire ou une modification inattendue du Z-buffer. La règle générale est donc : attendre la fin du Blitter avant de le reprogrammer.

L'Object Processor demande encore davantage de prudence, notamment pour le registre OLP (Object List Pointer). Il ne faut pas modifier directement OLP depuis le 68000 pendant que l'OP peut être actif. Une valeur de pointeur partiellement écrite pourrait être observée entre les deux transferts 16 bits nécessaires au 68000.

Lorsqu'un changement d'Object List est nécessaire, il faut utiliser une méthode de synchronisation appropriée. Une possibilité consiste à effectuer la modification à un moment où l'Object Processor ne risque pas d'utiliser la valeur. Une autre consiste à confier l'écriture au GPU, qui peut réaliser l'opération selon le chemin atomique prévu pour ce type de mise à jour. Dans tous les cas, l'OP ne doit jamais recevoir un OLP intermédiaire.

Le même principe s'applique aux descripteurs de l'Object List. Une phrase que l'OP est susceptible de lire ne doit pas être reconstruite progressivement sous ses yeux. Pour les structures complexes fréquemment mises à jour, le double buffering constitue généralement une solution beaucoup plus sûre.

Avec un double tampon, un composant consomme une version pendant que l'autre version est modifiée. Pour une Object List, l'OP peut parcourir la liste A pendant que le 68000 ou le GPU prépare la liste B. Une fois B entièrement construite et terminée par son objet STOP, les deux listes peuvent être permutées à un point de synchronisation approprié.

Le même principe peut être appliqué au rendu graphique. Le Blitter et le GPU construisent une image dans un framebuffer pendant que l'Object Processor affiche l'autre. Une fois le rendu terminé, les rôles sont échangés. Cette méthode évite à la fois les structures partiellement écrites et les effets visuels comme le tearing.

Le double buffering audio répond à une contrainte comparable. Le DSP peut préparer un tampon d'échantillons pendant que l'interface audio consomme le précédent. La permutation n'a lieu que lorsque le prochain bloc est prêt. Cette réserve permet également d'absorber de petites variations de latence provoquées par la contention de la DRAM.

Pour les files de commandes et d'événements, de simples flags ne suffisent pas toujours. Lorsque plusieurs événements peuvent être produits avant que le consommateur ne les traite, il est préférable d'utiliser des index monotones, c'est-à-dire des compteurs de production et de consommation qui progressent continuellement plutôt que de simples indicateurs binaires.

Un producteur peut ainsi incrémenter son index à chaque nouvelle commande, tandis que le consommateur possède son propre index indiquant jusqu'où il a traité la file. La différence entre les deux permet de déterminer combien d'éléments restent disponibles. Cette organisation réduit le risque qu'un nouvel événement remplace un flag encore actif et fasse perdre un événement précédent.

La synchronisation sur Jaguar ne consiste donc pas à gérer une cohérence de caches, puisque l'architecture ne possède pas les caches classiques qui imposeraient ce problème. Elle consiste surtout à garantir l'ordre des écritures, leur atomicité et la propriété temporaire des structures partagées. Le fait qu'un long du 68000 soit transféré sous forme de deux mots rend cette question particulièrement importante.

Une programmation robuste doit ainsi respecter quelques règles fondamentales : écrire complètement les données avant de publier un flag, laisser le consommateur effacer ce flag, arrêter le GPU ou le DSP avant de modifier leur code, attendre la fin du Blitter avant de reprogrammer ses registres et ne pas changer OLP depuis le 68000 pendant que l'Object Processor peut l'utiliser. Les Object Lists, les tampons audio et les surfaces de rendu gagnent à utiliser le double buffering, tandis que les files d'événements doivent employer des index monotones lorsqu'un simple indicateur prêt/occupé risquerait de perdre des informations.

Optimisation et bande passante

Le pic théorique 64 bits par tic n'est pas disponible simultanément pour tous. Une opération mal alignée peut diviser la bande passante par plusieurs facteurs.



Dernière mise à jour : Vendredi, le 12 Novembre 2021