No puede hacer esto en general, pero en algunos sentidos, puede hacerlo, y ha habido algunos casos históricos en los que realmente tuvo que hacerlo.
El Atari 2600 (o Atari Video Computer System) fue uno de los primeros sistemas de videojuegos domésticos y se lanzó por primera vez en 1978. A diferencia de los sistemas posteriores de la era, Atari no podía permitirse darle al dispositivo un búfer de cuadros, lo que significa que la CPU tenía ejecutar código en cada línea de exploración para determinar qué producir: si este código tomara 17.08 microsegundos para ejecutarse (el intervalo HBlank), los gráficos no se establecerían correctamente antes de que la línea de exploración comenzara a dibujarlos. Peor aún, si el programador quería dibujar contenido más complejo de lo que normalmente permitía Atari, tenía que medir los tiempos exactos para las instrucciones y cambiar los registros gráficos a medida que se dibujaba el haz, con un lapso de 57,29 microsegundos para toda la línea de exploración.
Sin embargo, el Atari 2600, como muchos otros sistemas basados en el 6502, tenía una característica muy importante que permitía la cuidadosa administración del tiempo requerida para este escenario: la CPU, la RAM y la señal de TV se salieron de los relojes basados en el mismo maestro reloj. La señal de TV salió de un reloj de 3.98 MHz, dividiendo las veces anteriores en un número entero de "relojes de color" que administraban la señal de TV, y un ciclo de los relojes de CPU y RAM fue exactamente tres relojes de color, permitiendo que el reloj de la CPU sea Una medida precisa del tiempo en relación con la señal de TV de progreso actual. (Para obtener más información sobre esto, consulte la Guía del programador de Stella , escrita para el emulador Stella Atari 2600 ).
Este entorno operativo, además, significaba que cada instrucción de CPU tenía una cantidad definida de ciclos que tomaría en cada caso, y muchos desarrolladores de 6502 publicaron esta información en tablas de referencia. Por ejemplo, considere esta entrada para la CMP
instrucción (Comparar memoria con acumulador), tomada de esta tabla :
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
Utilizando toda esta información, Atari 2600 (y otros desarrolladores de 6502) pudieron determinar exactamente cuánto tiempo tardó en ejecutarse su código y crear rutinas que hicieron lo que necesitaban y cumplían con los requisitos de sincronización de señal de TV de Atari. Y debido a que este tiempo era tan exacto (especialmente para instrucciones que perdían el tiempo como NOP), incluso pudieron usarlo para modificar los gráficos a medida que se dibujaban.
Por supuesto, el 6502 de Atari es un caso muy específico, y todo esto es posible solo porque el sistema tenía todo lo siguiente:
- Un reloj maestro que funcionaba todo, incluida la RAM. Los sistemas modernos tienen relojes independientes para la CPU y la RAM, con el reloj RAM a menudo más lento y los dos no necesariamente sincronizados.
- Sin almacenamiento en caché de ningún tipo: el 6502 siempre accedía a DRAM directamente. Los sistemas modernos tienen memorias caché SRAM que hacen que sea más difícil predecir el estado; aunque quizás todavía sea posible predecir el comportamiento de un sistema con una memoria caché, definitivamente es más difícil.
- No hay otros programas ejecutándose simultáneamente: el programa en el cartucho tenía un control completo del sistema. Los sistemas modernos ejecutan múltiples programas a la vez utilizando algoritmos de programación no deterministas.
- Una velocidad de reloj lo suficientemente lenta como para que las señales puedan viajar a través del sistema a tiempo. En un sistema moderno con velocidades de reloj de 4 GHz (por ejemplo), se necesita un fotón de luz de 6.67 ciclos de reloj para recorrer la longitud de una placa base de medio metro; nunca podría esperar que un procesador moderno interactúe con otra cosa en la placa en solo un ciclo, ya que se necesita más de un ciclo para que una señal en el tablero llegue incluso al dispositivo.
- Una velocidad de reloj bien definida que rara vez cambia (1,19 MHz en el caso del Atari): las velocidades de la CPU de los sistemas modernos cambian todo el tiempo, mientras que un Atari no podría hacer esto sin afectar también la señal de TV.
- Tiempos de ciclo publicados: el x86 no define cuánto tiempo lleva cualquiera de sus instrucciones.
Todas estas cosas se unieron para crear un sistema donde era posible crear conjuntos de instrucciones que tomaron una cantidad exacta de tiempo, y para esta aplicación, eso es exactamente lo que se exigía. La mayoría de los sistemas no tienen este grado de precisión simplemente porque no es necesario: los cálculos se realizan cuando se realizan o si se necesita una cantidad de tiempo exacta, se puede consultar un reloj independiente. Pero si la necesidad es correcta (como en algunos sistemas integrados), todavía puede aparecer y podrá determinar con precisión cuánto tiempo tarda su código en ejecutarse en estos entornos.
Y también debo agregar el gran descargo de responsabilidad masivo de que todo esto solo se aplica a la construcción de un conjunto de instrucciones de ensamblaje que llevará una cantidad exacta de tiempo. Si lo que desea hacer es tomar una pieza arbitraria de ensamblaje, incluso en estos entornos, y preguntar "¿Cuánto tiempo lleva ejecutar esto?", Categóricamente no puede hacer eso, ese es el problema de detención , que se ha demostrado que no tiene solución.
EDITAR 1: En una versión anterior de esta respuesta, dije que el Atari 2600 no tenía forma de informar al procesador de dónde estaba en la señal de TV, lo que lo obligó a mantener todo el programa contado y sincronizado desde el principio. Como se me señaló en los comentarios, esto es cierto para algunos sistemas como el ZX Spectrum, pero no es cierto para el Atari 2600, ya que contiene un registro de hardware que detiene la CPU hasta que se produzca el siguiente intervalo de supresión horizontal, así como una función para comenzar el intervalo de supresión vertical a voluntad. Por lo tanto, el problema de contar los ciclos se limita a cada línea de exploración, y solo se vuelve exacto si el desarrollador desea cambiar el contenido a medida que se dibuja la línea de exploración.