stringtranslate.com

Ranura de retardo

En arquitectura informática , una ranura de retardo es una ranura de instrucción que se ejecuta sin los efectos de una instrucción anterior. [1] La forma más común es una única instrucción arbitraria ubicada inmediatamente después de una instrucción de rama en una arquitectura RISC o DSP ; Esta instrucción se ejecutará incluso si se toma la rama anterior. Esto hace que la instrucción se ejecute fuera de orden en comparación con su ubicación en el código del lenguaje ensamblador original .

Los diseños de procesadores modernos generalmente no utilizan ranuras de retardo y, en su lugar, realizan formas cada vez más complejas de predicción de bifurcaciones . En estos sistemas, la CPU pasa inmediatamente a lo que cree que será el lado correcto de la rama y, por lo tanto, elimina la necesidad de que el código especifique alguna instrucción no relacionada, que puede no siempre ser obvia en tiempo de compilación. Si la suposición es errónea y es necesario llamar al otro lado de la rama, esto puede provocar un retraso prolongado. Esto ocurre tan raramente que la velocidad para evitar el intervalo de retraso se compensa fácilmente con un menor número de decisiones equivocadas.

Tubería

Una unidad central de procesamiento generalmente ejecuta instrucciones del código de máquina mediante un proceso de cuatro pasos; la instrucción primero se lee de la memoria, luego se decodifica para comprender lo que se debe realizar, luego esas acciones se ejecutan y, finalmente, los resultados se escriben nuevamente en la memoria. En los primeros diseños, cada una de estas etapas se realizaba en serie, de modo que las instrucciones requerían un múltiplo del ciclo de reloj de la máquina para completarse. Por ejemplo, en el Zilog Z80 , el número mínimo de relojes necesarios para completar una instrucción era cuatro, pero podía llegar a 23 relojes para algunas instrucciones (pocas). [2]

En cualquier etapa dada del procesamiento de la instrucción, sólo está involucrada una parte del chip. Por ejemplo, durante la etapa de ejecución, normalmente solo la unidad lógica aritmética (ALU) está activa, mientras que otras unidades, como las que interactúan con la memoria principal o decodifican la instrucción, están inactivas. Una forma de mejorar el rendimiento general de una computadora es mediante el uso de un canal de instrucciones . Esto agrega algunos circuitos adicionales para mantener los estados intermedios de la instrucción a medida que fluye a través de las unidades. Si bien esto no mejora el tiempo del ciclo de una sola instrucción, la idea es permitir que una segunda instrucción use las otras subunidades de la CPU cuando la instrucción anterior haya avanzado. [3]

Por ejemplo, mientras una instrucción utiliza la ALU, la siguiente instrucción del programa puede estar en el decodificador y una tercera puede recuperarse de la memoria. En esta disposición de tipo línea de montaje , el número total de instrucciones procesadas en cualquier momento se puede mejorar hasta en el número de etapas de la tubería. En el Z80, por ejemplo, una tubería de cuatro etapas podría mejorar cuatro veces el rendimiento general. Sin embargo, debido a la complejidad del tiempo de instrucción, esto no sería fácil de implementar. La arquitectura de conjunto de instrucciones (ISA) mucho más simple del MOS 6502 permitió incluir una canalización de dos etapas, lo que le dio un rendimiento que era aproximadamente el doble que el del Z80 a cualquier velocidad de reloj determinada. [4]

Problemas de ramificación

Un problema importante con la implementación de canalizaciones en los primeros sistemas era que las instrucciones tenían recuentos de ciclos muy variables. Por ejemplo, la instrucción para sumar dos valores a menudo se ofrecería en múltiples versiones, u códigos de operación , que variaban según el lugar en el que se leían los datos. Una versión de addpodría tomar el valor encontrado en un registro del procesador y agregarlo al valor en otro, otra versión podría agregar el valor encontrado en la memoria a un registro, mientras que otra podría agregar el valor de una ubicación de memoria a otra ubicación de memoria. Cada una de estas instrucciones requiere una cantidad diferente de bytes para representarla en la memoria, lo que significa que requieren diferentes cantidades de tiempo para recuperarse, pueden requerir múltiples viajes a través de la interfaz de memoria para recopilar valores, etc. Esto complica enormemente la lógica de la canalización. Uno de los objetivos del concepto de diseño del chip RISC era eliminar estas variantes para simplificar la lógica de la canalización, lo que conduce a la canalización RISC clásica que completa una instrucción en cada ciclo.

Sin embargo, surge un problema en los sistemas de tuberías que puede ralentizar el rendimiento. Esto ocurre cuando la siguiente instrucción puede cambiar dependiendo de los resultados de la última. En la mayoría de los sistemas, esto sucede cuando se produce una bifurcación . Por ejemplo, considere el siguiente pseudocódigo:

arriba: leer un número de la memoria y almacenarlo en un registro leer otro número y almacenarlo en un registro diferente sumar los dos números en un tercer registro escribe el resultado en la memoria leer un número de la memoria y almacenarlo en otro registro ...

En este caso, el programa es lineal y se puede canalizar fácilmente. Tan pronto como readse haya leído y decodificado la primera instrucción, readse podrá leer la segunda instrucción de la memoria. Cuando el primero se mueve para ejecutarse, se addlee de la memoria mientras el segundo readse decodifica, y así sucesivamente. Aunque todavía se necesita la misma cantidad de ciclos para completar el primero read, cuando se completa, el valor del segundo está listo y la CPU puede agregarlos inmediatamente. En un procesador no canalizado, las primeras cuatro instrucciones tardarán 16 ciclos en completarse, en uno canalizado, solo se necesitan cinco.

Ahora considere lo que ocurre cuando se agrega una rama:

arriba: leer un número de la memoria y almacenarlo en un registro leer otro número y almacenarlo en un registro diferente sumar los dos números en un tercer registro si el resultado en el tercer registro es mayor que 1000, regrese al principio: (si no es así) escribe el resultado en la memoria leer un número de la memoria y almacenarlo en otro registro ...

En este ejemplo, el resultado de la comparación en la línea cuatro hará que cambie la "siguiente instrucción"; A veces será lo siguiente writeen la memoria y otras veces será lo readsiguiente en la memoria. La canalización del procesador normalmente ya habrá leído la siguiente instrucción, la write, cuando la ALU haya calculado qué ruta tomará. Esto se conoce como riesgo de rama . Si tiene que volver al principio, la writeinstrucción debe descartarse y, readen su lugar, leerse de la memoria. Esto requiere un ciclo de instrucción completo, como mínimo, y da como resultado que la canalización esté vacía durante al menos una instrucción. Esto se conoce como "bloqueo de canalización" o "burbuja" y, dependiendo del número de ramas en el código, puede tener un impacto notable en el rendimiento general.

Ranuras de retardo de rama

Una estrategia para abordar este problema es utilizar un intervalo de retraso , que se refiere al intervalo de instrucción después de cualquier instrucción que necesite más tiempo para completarse. En los ejemplos anteriores, la instrucción que requiere más tiempo es la bifurcación, que es, con diferencia, el tipo más común de intervalo de retardo, y se denomina más comúnmente intervalo de retardo de bifurcación .

En las primeras implementaciones, la instrucción que sigue a la rama se completaba con una no operación, o NOPsimplemente para completar la canalización y garantizar que el momento fuera el correcto, de modo que cuando NOPse cargara desde la memoria, la rama estuviera completa y el programa El contador podría actualizarse con el valor correcto. Esta sencilla solución desperdicia el tiempo de procesamiento disponible. En cambio, soluciones más avanzadas intentarían identificar otra instrucción, generalmente cercana en el código, para colocarla en la ranura de retardo para que se pueda realizar un trabajo útil.

En los ejemplos anteriores, la readinstrucción al final es completamente independiente, no depende de ninguna otra información y se puede ejecutar en cualquier momento. Esto lo hace adecuado para colocarlo en la ranura de retardo de rama. Normalmente esto sería manejado automáticamente por el programa ensamblador o compilador , que reordenaría las instrucciones:

leer un número de la memoria y almacenarlo en un registro leer otro número y almacenarlo en un registro diferente sumar los dos números en un tercer registro si el resultado en el tercer registro es mayor que 1000, regrese al principio leer un número de la memoria y almacenarlo en otro registro (si no es así) escribe el resultado en la memoria ...

Ahora, cuando la rama se está ejecutando, continúa y realiza la siguiente instrucción. En el momento en que la instrucción se lee en el procesador y comienza a decodificarse, el resultado de la comparación está listo y el procesador ahora puede decidir qué instrucción leer a continuación, la readde arriba o la writede abajo. Esto evita pérdidas de tiempo y mantiene la tubería llena en todo momento.

Encontrar una instrucción para llenar el espacio puede resultar complicado. Los compiladores generalmente tienen una "ventana" limitada para examinar y es posible que no encuentren una instrucción adecuada en ese rango de código. Además, la instrucción no puede basarse en ninguno de los datos contenidos en la sucursal; Si una addinstrucción toma un cálculo previo como una de sus entradas, esa entrada no puede ser parte del código en una rama que pueda tomarse. Decidir si esto es cierto puede ser muy complejo en presencia del cambio de nombre de registros , en el que el procesador puede colocar datos en registros distintos a los que especifica el código sin que el compilador se dé cuenta.

Otro efecto secundario es que se necesita un manejo especial al administrar puntos de interrupción en instrucciones, así como al realizar pasos durante la depuración dentro del intervalo de retardo de rama. Una interrupción no puede ocurrir durante un intervalo de retardo de bifurcación y se difiere hasta después del intervalo de retardo de bifurcación. [5] [6] Está prohibido o desaprobado colocar instrucciones de bifurcación en la ranura de retardo de bifurcación. [7] [8] [9]

El número ideal de espacios de retardo de rama en una implementación particular de la tubería está dictado por la cantidad de etapas de la tubería, la presencia de reenvío de registros , en qué etapa de la tubería se calculan las condiciones de la rama, si se utiliza o no un búfer de destino de rama (BTB). y muchos otros factores. Los requisitos de compatibilidad de software dictan que una arquitectura no puede cambiar el número de ranuras de retardo de una generación a la siguiente. Esto inevitablemente requiere que las implementaciones de hardware más nuevas contengan hardware adicional para garantizar que se siga el comportamiento arquitectónico a pesar de que ya no sea relevante.

Implementaciones

Las ranuras de retardo de rama se encuentran principalmente en arquitecturas DSP y arquitecturas RISC más antiguas . MIPS , PA-RISC (se puede especificar rama retrasada o no retrasada), [10] ETRAX CRIS , SuperH (las instrucciones de rama incondicional tienen una ranura de retardo), [11] Am29000 , [12] Intel i860 (las instrucciones de rama incondicional tienen una ranura de retardo), [13] MC88000 (se puede especificar rama retrasada o no retrasada), [14] y SPARC son arquitecturas RISC que tienen cada una una única ranura de retardo de rama; PowerPC , ARM , Alpha , V850 y RISC-V no tienen ninguno. Las arquitecturas DSP que tienen cada una una ranura de retardo de rama única incluyen μPD77230 [15] y VS DSP. SHARC DSP y MIPS-X utilizan una ranura de retardo de doble rama; [16] dicho procesador ejecutará un par de instrucciones después de una instrucción de bifurcación antes de que la bifurcación entre en vigor. Tanto TMS320C3x [17] como TMS320C4x [8] utilizan una ranura de retardo de rama triple. El TMS320C4x tiene ramas retardadas y no retardadas. [8]

El siguiente ejemplo muestra ramas retrasadas en lenguaje ensamblador para SHARC DSP, incluido un par después de la instrucción RTS. Los registros R0 a R9 se borran a cero en orden numérico (el registro borrado después de R6 es R7, no R9). Ninguna instrucción se ejecuta más de una vez.

 R0 = 0; LLAMADA fn (DB); /* llama a una función, debajo en la etiqueta "fn" */ R1 = 0; /* primer intervalo de retardo */ R2 = 0; /* segundo intervalo de retardo */ /***** discontinuidad aquí (la LLAMADA surte efecto) *****/ R6 = 0; /* el CALL/RTS vuelve aquí, no en "R1 = 0" */ Fin del SALTO (DB); R7 = 0; /* primer intervalo de retardo */ R8 = 0; /* segundo intervalo de retardo */ /***** discontinuidad aquí (el SALTO surte efecto) *****/ /* las siguientes 4 instrucciones se llaman desde arriba, como función "fn" */fn: R3 = 0; estrategia en tiempo real (base de datos); /* regresa al llamante, pasando los intervalos de retardo del llamante */ R4 = 0; /* primer intervalo de retardo */ R5 = 0; /* segundo intervalo de retardo */ /***** discontinuidad aquí (el RTS entra en vigor) *****/final: R9 = 0;


Ranura de retardo de carga

Una ranura de retardo de carga es una instrucción que se ejecuta inmediatamente después de una carga (de un registro de la memoria) pero no ve ni necesita esperar el resultado de la carga. Los intervalos de retraso de carga son muy poco comunes porque los retrasos de carga son muy impredecibles en el hardware moderno. Una carga puede satisfacerse desde la RAM o desde una caché, y puede verse ralentizada por la contención de recursos. Se observaron retrasos en la carga en los primeros diseños de procesadores RISC. El MIPS I ISA (implementado en los microprocesadores R2000 y R3000 ) sufre este problema.

El siguiente ejemplo es código ensamblador MIPS I y muestra una ranura de retardo de carga y una ranura de retardo de rama.

 lw v0 , 4 ( v1 ) # cargar palabra desde la dirección v1+4 en v0 nop # ranura de retardo de carga desperdiciada jr v0 # saltar a la dirección especificada por v0 nop # ranura de retardo de rama desperdiciada         

Ver también

Referencias

  1. ^ A. Patterson, David; L. Hennessy, John (1990). Arquitectura informática: un enfoque cuantitativo . Editores Morgan Kaufmann. pag. 275.ISBN​ 1-55860-069-8.
  2. ^ "Página de ensamblaje de MSX".
  3. ^ "CMSC 411 Conferencia 19, Canalización de reenvío de datos". Departamento de Ingeniería Eléctrica y Ciencias de la Computación del Condado de Baltimore de la Universidad de Maryland . Consultado el 22 de enero de 2020 .
  4. ^ Cox, Russ (3 de enero de 2011). "El MOS 6502 y el mejor maquetador del mundo".
  5. ^ "Procesador de señal avanzado μPD77230" (PDF) . págs.38(3-39), 70(3-41) . Consultado el 17 de noviembre de 2023 .
  6. ^ "Guía del usuario de TMS320C4x" (PDF) . pag. 75(3-15) . Consultado el 2 de diciembre de 2023 .
  7. ^ "Procesador de señal avanzado μPD77230" (PDF) . pag. 191(4-76) . Consultado el 28 de octubre de 2023 .
  8. ^ a b "Guía del usuario de TMS320C4x" (PDF) . pag. 171(7-9) . Consultado el 29 de octubre de 2023 .
  9. ^ "Manual del usuario del microprocesador RISC MC88100" (PDF) . pag. 88(3-33) . Consultado el 30 de diciembre de 2023 .
  10. ^ DeRosa, John A.; Levy, Henry M. "Una evaluación de arquitecturas de sucursales". pag. 1 . Consultado el 27 de enero de 2024 .
  11. ^ "Manual de hardware SH7020 y SH7021Motor SuperH RISC". pag. 42,70 . Consultado el 17 de diciembre de 2023 .
  12. ^ "Evaluación y programación de la tercera edición de la familia RISC 29K - BORRADOR" (PDF) . pag. 54 . Consultado el 20 de diciembre de 2023 .
  13. ^ "Manual de referencia del programador del microprocesador i860 ™ de 64 bits" (PDF) . pag. 70(5-11) . Consultado el 21 de diciembre de 2023 .
  14. ^ "Manual del usuario del microprocesador RISC MC88100" (PDF) . pag. 81(3-26) . Consultado el 21 de diciembre de 2023 .
  15. ^ "Procesador de señal avanzado μPD77230" (PDF) . pag. 191(4-76) . Consultado el 5 de noviembre de 2023 .
  16. ^ "Conjunto de instrucciones y manual del programador de MIPS-X" (PDF) . pag. 18 . Consultado el 3 de diciembre de 2023 .
  17. ^ "El procesador de señal digital de punto flotante TMS320C30" (PDF) . ti.com. pag. 14 . Consultado el 4 de noviembre de 2023 .

enlaces externos