Vous ne pouvez pas le faire en général, mais dans certains sens, vous le pouvez beaucoup, et il y a eu quelques cas historiques dans lesquels vous avez dû le faire.
L' Atari 2600 (ou Atari Video Computer System) était l'un des premiers systèmes de jeux vidéo à domicile et a été publié pour la première fois en 1978. Contrairement aux systèmes ultérieurs de l'époque, Atari ne pouvait pas se permettre de donner à l'appareil un tampon de trame, ce qui signifie que le processeur avait pour exécuter du code à chaque ligne de balayage afin de déterminer ce qu'il faut produire - si ce code prenait plus de 17,08 microsecondes pour s'exécuter (intervalle HBlank), les graphiques ne seraient pas correctement définis avant que la ligne de balayage ne commence à les dessiner. Pire encore, si le programmeur voulait dessiner un contenu plus complexe que ce qu'Atari autorisait normalement, il devait mesurer les heures exactes des instructions et modifier les registres graphiques au fur et à mesure du tracé du faisceau, avec une durée de 57,29 microsecondes pour toute la ligne de balayage.
Cependant, l'Atari 2600, comme de nombreux autres systèmes basés sur le 6502, avait une caractéristique très importante qui permettait la gestion minutieuse du temps requise pour ce scénario: le processeur, la RAM et le signal TV fonctionnaient tous sur des horloges basées sur le même maître l'horloge. Le signal TV a fonctionné sur une horloge de 3,98 MHz, divisant les temps ci-dessus en un nombre entier d '"horloges de couleur" qui ont géré le signal TV, et un cycle des horloges CPU et RAM était exactement de trois horloges couleur, permettant à l'horloge du CPU d'être une mesure précise du temps par rapport au signal TV de progression actuel. (Pour plus d'informations à ce sujet, consultez le Guide du programmeur Stella , écrit pour l' émulateur Stella Atari 2600 ).
Cet environnement d'exploitation, en outre, signifiait que chaque instruction CPU avait une quantité définie de cycles qu'elle prendrait dans chaque cas, et de nombreux développeurs 6502 ont publié ces informations dans des tableaux de référence. Par exemple, considérez cette entrée pour l' CMP
instruction (Comparer la mémoire avec l'accumulateur), extraite de ce tableau :
CMP Compare Memory with Accumulator
A - M N Z C I D V
+ + + - - -
addressing assembler opc bytes cycles
--------------------------------------------
immediate CMP #oper C9 2 2
zeropage CMP oper C5 2 3
zeropage,X CMP oper,X D5 2 4
absolute CMP oper CD 3 4
absolute,X CMP oper,X DD 3 4*
absolute,Y CMP oper,Y D9 3 4*
(indirect,X) CMP (oper,X) C1 2 6
(indirect),Y CMP (oper),Y D1 2 5*
* add 1 to cycles if page boundary is crossed
En utilisant toutes ces informations, Atari 2600 (et d'autres développeurs 6502) ont pu déterminer exactement combien de temps leur code mettait à s'exécuter, et construire des routines qui faisaient ce dont elles avaient besoin et respectaient toujours les exigences de synchronisation du signal TV d'Atari. Et parce que ce timing était si précis (en particulier pour les instructions de perte de temps comme NOP), ils ont même pu l'utiliser pour modifier les graphiques au fur et à mesure qu'ils étaient dessinés.
Bien sûr, le 6502 d'Atari est un cas très spécifique, et tout cela n'est possible que parce que le système avait toutes les caractéristiques suivantes:
- Une horloge maître qui a tout exécuté, y compris la RAM. Les systèmes modernes ont des horloges indépendantes pour le CPU et la RAM, l'horloge RAM étant souvent plus lente et les deux n'étant pas nécessairement synchronisées.
- Aucune mise en cache d'aucune sorte - le 6502 a toujours accédé directement à la DRAM. Les systèmes modernes ont des caches SRAM qui rendent plus difficile la prédiction de l'état - bien qu'il soit peut-être encore possible de prédire le comportement d'un système avec un cache, c'est certainement plus difficile.
- Aucun autre programme fonctionnant simultanément - le programme sur la cartouche avait un contrôle complet du système. Les systèmes modernes exécutent plusieurs programmes à la fois en utilisant des algorithmes de planification non déterministes.
- Une vitesse d'horloge suffisamment lente pour que les signaux puissent traverser le système dans le temps. Sur un système moderne avec des vitesses d'horloge de 4 GHz (par exemple), il faut un photon de lumière 6,67 cycles d'horloge pour parcourir la longueur d'une carte mère d'un demi-mètre - vous ne pourriez jamais vous attendre à ce qu'un processeur moderne interagisse avec autre chose sur la carte en un seul cycle, car il faut plus d'un cycle pour qu'un signal sur la carte atteigne même l'appareil.
- Une vitesse d'horloge bien définie qui change rarement (1,19 MHz dans le cas de l'Atari) - les vitesses du processeur des systèmes modernes changent tout le temps, tandis qu'un Atari ne pourrait pas le faire sans affecter également le signal TV.
- Délais de cycle publiés - le x86 ne définit pas la durée de ses instructions.
Toutes ces choses se sont réunies pour créer un système où il était possible de créer des ensembles d'instructions qui ont pris un temps exact - et pour cette application, c'est exactement ce qui était demandé. La plupart des systèmes n'ont pas ce degré de précision simplement parce que cela n'est pas nécessaire - les calculs sont effectués lorsqu'ils sont terminés, ou si une durée exacte est nécessaire, une horloge indépendante peut être interrogée. Mais si le besoin est bon (comme sur certains systèmes embarqués), il peut toujours apparaître, et vous pourrez déterminer avec précision le temps nécessaire à l'exécution de votre code dans ces environnements.
Et je devrais également ajouter le grand avertissement massif que tout cela ne s'applique qu'à la construction d' un ensemble d'instructions d'assemblage qui prendra un temps exact. Si ce que vous voulez faire est de prendre un assemblage arbitraire, même dans ces environnements, et de demander "Combien de temps cela prend-il pour s'exécuter?", Vous ne pouvez catégoriquement pas le faire - c'est le problème de l' arrêt , qui s'est avéré insoluble.
EDIT 1: Dans une version précédente de cette réponse, j'ai déclaré que l'Atari 2600 n'avait aucun moyen d'informer le processeur de l'endroit où il se trouvait dans le signal TV, ce qui l'a forcé à garder le programme entier compté et synchronisé dès le début. Comme je l'ai souligné dans les commentaires, cela est vrai pour certains systèmes comme le ZX Spectrum, mais ce n'est pas le cas de l'Atari 2600, car il contient un registre matériel qui arrête le processeur jusqu'à ce que le prochain intervalle de suppression horizontal se produise, ainsi que une fonction pour commencer à volonté l'intervalle de suppression verticale. Par conséquent, le problème des cycles de comptage est limité à chaque ligne de balayage et ne devient exact que si le développeur souhaite modifier le contenu pendant le tracé de la ligne de balayage.