Leí en mi libro que deberíamos tener un pequeño número de registros (como 32 registros)
¿Cuáles son algunas de las razones?
Leí en mi libro que deberíamos tener un pequeño número de registros (como 32 registros)
¿Cuáles son algunas de las razones?
Algunos obvios:
Ocupan espacio en la codificación de tus instrucciones. Si tuviera 256 registros, por ejemplo, necesitaría usar 8 bits en una instrucción solo para especificar un registro único. Esto podría aumentar el tamaño total de las instrucciones o limitar los tipos de instrucciones que se pueden codificar; tener menos registros, en términos generales, hace que su codificación de instrucciones sea más densa.
Desde un punto de vista práctico, hay un límite a la cantidad de registros que son útiles para las aplicaciones, y 32 está en el extremo superior de eso; ¡Algunas aplicaciones terminan usando todos los registros! 16 (como se ve en ARM, entre otros) es generalmente suficiente, y algunas arquitecturas se quedan con menos (como x86 de 32 bits, que solo tiene 8).
Ocupan espacio físico en la CPU. Podría haber mejores cosas para las que podría usarlo, como más caché o más unidades de ejecución.
Dicho todo esto, las CPU modernas a menudo tienen toneladas de registros. Por ejemplo, una CPU Intel Haswell tiene 168 registros enteros! Lo que es diferente, sin embargo, es que estos registros no están expuestos directamente en el conjunto de instrucciones; en su lugar, se utilizan para cambiar el nombre del registro para admitir la ejecución fuera de orden y especulativa.
Hay diferentes puntos de vista sobre esto, y van y vienen como modas a medida que cambian los puntos clave tecnológicos.
Desde el punto de vista del diseño del conjunto de instrucciones, una vista (se me presentó en la década de 1970) es que debería tener 0, 1 o registros infinitos.
0 e infinito son esencialmente el mismo caso, ambos son modelos de almacenamiento planos. 1 registro se llama el acumulador, y como es el objetivo predeterminado para la mayoría de las instrucciones, no consume espacio en las instrucciones para abordar.
Históricamente, un número "pequeño" de registros era de 4 u 8 registros, siendo 32 una aproximación bastante cercana al infinito cuando las puertas o los registros eran caros.
El problema con un número tan grande de registros es abordarlos: para direccionar 32 registros se necesitan 5 bits, y si van a ser de propósito general, muchas instrucciones deben abordar 2 fuentes y un destino, es decir, 15 bits desperdiciados en un instrucción individual. (Las instrucciones se clasifican en términos de la cantidad de direcciones que necesitan; esta es una instrucción de tres direcciones).
Por lo tanto, es obvio que 32 registros de GP tuvieron que esperar hasta que las instrucciones de 32 bits fueran asequibles, y que incluso en ese momento, se puede desperdiciar casi la mitad de su tamaño de archivo ejecutable simplemente dirigiéndose a los registros.
Lo que realmente desea no es una pequeña cantidad de registros, sino una pequeña cantidad de espacio desperdiciado que los aborda.
El enfoque alternativo de "acumulador" ahorra 5 bits al escribir siempre en el mismo registro 'o 10 bits si el acumulador es también una de las fuentes, pero cuesta unas cuantas instrucciones más de "mover" hacia / desde el acumulador. Es decir, el acumulador permite instrucciones mucho más pequeñas de "una dirección".
Las técnicas de compilación inteligentes se pueden usar para reordenar los cálculos para minimizar el número de "movimientos" desperdiciados, y las técnicas superescalares podrían usar varios acumuladores físicos que siguen el método de la arquitectura simple, eliminando otros "movimientos" o reprogramándolos en paralelo con otras operaciones.
Otro enfoque que permite "registros infinitos" sin desperdiciar espacio de direcciones es la apilar la máquina , donde en lugar de el acumulador, el destino predeterminado es "TOS" o "Top-of-Stack", que es efectivamente una dirección base en un gran banco de registros, y las pequeñas compensaciones de este se codifican en menos de 5 bits para otros operandos.
Nota histórica: una aproximación a esto fue la "ventana de registro deslizante" de la arquitectura SPARC que aborda un subconjunto local de un mayor número de registros.
El ARM intercambia registros adicionales durante los controladores de interrupción por motivos similares. También tiene sus conjuntos de instrucciones "Pulgar" para aumentar la densidad del código, pero no los he estudiado.
Estas arquitecturas lógicas y otras se quedaron en el camino en la década de 1980, ya que la aparente simplicidad del RISC directo le permitió llegar al mercado más rápido con nuevos procesos y adoptar más fácilmente técnicas como la canalización, la superescala y la reordenación.
Las últimas técnicas demostraron ser igualmente aplicables a las arquitecturas CISC, especialmente el x86 que sobrevivió en su enorme base de código heredado. Probablemente también son útiles para las arquitecturas de acumuladores y pilas, pero no se han aplicado extensivamente a ellas.
Lea otras preguntas en las etiquetas microprocessor digital-logic register