Canalización RISC clásica

Canalización de instrucciones

En la historia del hardware informático , algunas de las primeras unidades centrales de procesamiento de ordenador con conjunto de instrucciones reducido (CPU RISC) utilizaban una solución arquitectónica muy similar, ahora denominada canalización RISC clásica . Esas CPU eran: MIPS , SPARC , Motorola 88000 y, más tarde, la CPU DLX, inventada para la educación.

Cada uno de estos diseños RISC escalares clásicos busca e intenta ejecutar una instrucción por ciclo . El concepto común principal de cada diseño es una secuencia de instrucciones de ejecución de cinco etapas . Durante el funcionamiento, cada etapa de la secuencia trabaja en una instrucción a la vez. Cada una de estas etapas consta de un conjunto de flip-flops para mantener el estado y una lógica combinacional que opera en las salidas de esos flip-flops.

El clásico pipeline RISC de cinco etapas

Proceso básico de cinco etapas en una máquina RISC (IF = obtención de instrucción , ID = decodificación de instrucción, EX = ejecución, MEM = acceso a memoria, WB = reescritura de registro). El eje vertical representa las instrucciones sucesivas; el eje horizontal representa el tiempo. Por lo tanto, en la columna verde, la instrucción más temprana se encuentra en la etapa WB y la última instrucción se encuentra en la etapa de obtención de instrucciones.

Recuperación de instrucciones

Las instrucciones residen en una memoria que tarda un ciclo en leerse. Esta memoria puede estar dedicada a la SRAM o a una caché de instrucciones . El término "latencia" se utiliza a menudo en informática y significa el tiempo que transcurre desde que se inicia una operación hasta que se completa. Por lo tanto, la obtención de instrucciones tiene una latencia de un ciclo de reloj (si se utiliza una SRAM de un solo ciclo o si la instrucción estaba en la caché). Por lo tanto, durante la etapa de obtención de instrucciones , se obtiene una instrucción de 32 bits de la memoria de instrucciones.

El contador de programa , o PC, es un registro que contiene la dirección que se presenta a la memoria de instrucciones. La dirección se presenta a la memoria de instrucciones al comienzo de un ciclo. Luego, durante el ciclo, la instrucción se lee de la memoria de instrucciones y, al mismo tiempo, se realiza un cálculo para determinar el próximo PC. El próximo PC se calcula incrementando el PC en 4 y eligiendo si se toma ese como el próximo PC o se toma el resultado de un cálculo de bifurcación/salto como el próximo PC. Tenga en cuenta que en RISC clásico, todas las instrucciones tienen la misma longitud. (Esto es algo que separa a RISC de CISC [1] ). En los diseños RISC originales, el tamaño de una instrucción es de 4 bytes, por lo que siempre agregue 4 a la dirección de la instrucción, pero no use PC + 4 para el caso de una bifurcación, un salto o una excepción (consulte bifurcaciones retrasadas , a continuación). (Tenga en cuenta que algunas máquinas modernas usan algoritmos más complicados ( predicción de bifurcación y predicción de objetivo de bifurcación ) para adivinar la siguiente dirección de instrucción).

Decodificación de instrucciones

Otra cosa que separa las primeras máquinas RISC de las máquinas CISC anteriores es que RISC no tiene microcódigo . [2] En el caso de las instrucciones microcodificadas CISC, una vez extraídas de la caché de instrucciones, los bits de instrucción se desplazan hacia abajo en la tubería, donde la lógica combinacional simple en cada etapa de la tubería produce señales de control para la ruta de datos directamente desde los bits de instrucción. En esos diseños CISC, se realiza muy poca decodificación en la etapa tradicionalmente llamada etapa de decodificación. Una consecuencia de esta falta de decodificación es que se deben utilizar más bits de instrucción para especificar lo que hace la instrucción. Eso deja menos bits para cosas como los índices de registro.

Todas las instrucciones MIPS, SPARC y DLX tienen como máximo dos entradas de registro. Durante la etapa de decodificación, los índices de estos dos registros se identifican dentro de la instrucción y se presentan a la memoria de registros como la dirección. De esta manera, los dos registros nombrados se leen desde el archivo de registros . En el diseño MIPS, el archivo de registros tenía 32 entradas.

Al mismo tiempo que se lee el archivo de registros, la lógica de emisión de instrucciones en esta etapa determina si el pipeline está listo para ejecutar la instrucción en esta etapa. Si no lo está, la lógica de emisión hace que tanto la etapa de obtención de instrucciones como la etapa de decodificación se detengan. En un ciclo de detención, los flip flops de entrada no aceptan nuevos bits, por lo que no se realizan nuevos cálculos durante ese ciclo.

Si la instrucción decodificada es una bifurcación o un salto, la dirección de destino de la bifurcación o del salto se calcula en paralelo con la lectura del archivo de registros. La condición de la bifurcación se calcula en el ciclo siguiente (después de leer el archivo de registros) y, si se realiza la bifurcación o si la instrucción es un salto, se asigna al PC de la primera etapa el destino de la bifurcación, en lugar del PC incrementado que se ha calculado. Algunas arquitecturas hicieron uso de la unidad lógica aritmética (ALU) en la etapa de ejecución, a costa de una ligera disminución del rendimiento de las instrucciones.

La etapa de decodificación terminó con una gran cantidad de hardware: MIPS tiene la posibilidad de ramificarse si dos registros son iguales, por lo que un árbol AND de 32 bits de ancho se ejecuta en serie después de la lectura del archivo de registros, lo que crea una ruta crítica muy larga a través de esta etapa (lo que significa menos ciclos por segundo). Además, el cálculo del objetivo de la ramificación generalmente requería una adición de 16 bits y un incrementador de 14 bits. La resolución de la ramificación en la etapa de decodificación hizo posible tener solo una penalización por predicción errónea de la ramificación de un solo ciclo. Dado que las ramificaciones se tomaban muy a menudo (y, por lo tanto, se predecían incorrectamente), era muy importante mantener baja esta penalización.

Ejecutar

La etapa de ejecución es donde se lleva a cabo el cálculo real. Normalmente, esta etapa consta de una ALU y también de un desplazador de bits. También puede incluir un multiplicador y divisor de varios ciclos.

La ALU es responsable de realizar operaciones booleanas (and, or, not, nand, nor, xor, xnor) y también de realizar sumas y restas de números enteros. Además del resultado, la ALU normalmente proporciona bits de estado, como si el resultado fue 0 o no, o si se produjo un desbordamiento.

El cambiador de bits es responsable del cambio y las rotaciones.

Las instrucciones en estas máquinas RISC simples se pueden dividir en tres clases de latencia según el tipo de operación:

  • Operación registro-registro (latencia de ciclo único): suma, resta, comparación y operaciones lógicas. Durante la etapa de ejecución, los dos argumentos se enviaban a una ALU simple, que generaba el resultado al final de la etapa de ejecución.
  • Referencia de memoria (latencia de dos ciclos). Todas las cargas se realizan desde la memoria. Durante la etapa de ejecución, la ALU agregó los dos argumentos (un registro y un desplazamiento constante) para producir una dirección virtual al final del ciclo.
  • Instrucciones multiciclo (latencia de varios ciclos). Multiplicación y división de números enteros y todas las operaciones de punto flotante . Durante la etapa de ejecución, los operandos de estas operaciones se alimentaban a la unidad de multiplicación/división multiciclo. El resto de la secuencia de comandos quedaba libre para continuar la ejecución mientras la unidad de multiplicación/división hacía su trabajo. Para evitar complicar la etapa de reescritura y la lógica de emisión, las instrucciones multiciclo escribían sus resultados en un conjunto separado de registros.

Acceso a la memoria

Si es necesario acceder a la memoria de datos, se hace en esta etapa.

Durante esta etapa, las instrucciones de latencia de un solo ciclo simplemente envían sus resultados a la siguiente etapa. Este reenvío garantiza que tanto las instrucciones de uno como de dos ciclos siempre escriban sus resultados en la misma etapa del proceso, de modo que solo se pueda usar un puerto de escritura en el archivo de registros y esté siempre disponible.

Para el almacenamiento en caché de datos mapeados directamente y etiquetados virtualmente, la más simple de las numerosas organizaciones de almacenamiento en caché de datos , se utilizan dos SRAM , una que almacena datos y la otra que almacena etiquetas.

Escritura diferida

Durante esta etapa, tanto las instrucciones de un solo ciclo como las de dos ciclos escriben sus resultados en el archivo de registros. Tenga en cuenta que dos etapas diferentes acceden al archivo de registros al mismo tiempo: la etapa de decodificación lee dos registros de origen, al mismo tiempo que la etapa de reescritura escribe el registro de destino de una instrucción anterior. En silicio real, esto puede ser un peligro (consulte a continuación para obtener más información sobre los peligros). Esto se debe a que uno de los registros de origen que se leen en la decodificación puede ser el mismo que el registro de destino que se escribe en la reescritura. Cuando eso sucede, las mismas celdas de memoria en el archivo de registros se leen y escriben al mismo tiempo. En silicio, muchas implementaciones de celdas de memoria no funcionarán correctamente cuando se lean y escriban al mismo tiempo.

Peligros

Hennessy y Patterson acuñaron el término “riesgo” para referirse a situaciones en las que las instrucciones en una cadena de montaje producirían respuestas erróneas.

Peligros estructurales

Los riesgos estructurales ocurren cuando dos instrucciones pueden intentar usar los mismos recursos al mismo tiempo. Las tuberías RISC clásicas evitaban estos riesgos replicando el hardware. En particular, las instrucciones de bifurcación podrían haber usado la ALU para calcular la dirección de destino de la bifurcación. Si la ALU se hubiera usado en la etapa de decodificación para ese propósito, una instrucción ALU seguida de una bifurcación habría hecho que ambas instrucciones intentaran usar la ALU simultáneamente. Es simple resolver este conflicto diseñando un sumador de destino de bifurcación especializado en la etapa de decodificación.

Peligros de los datos

Los riesgos de datos ocurren cuando una instrucción, programada a ciegas, intenta utilizar datos antes de que estos estén disponibles en el archivo de registro.

En la clásica cadena de montaje RISC, los riesgos para los datos se evitan de una de dos maneras:

Solución A. Pasar por alto

La omisión también se conoce como reenvío de operandos .

Supongamos que la CPU está ejecutando el siguiente fragmento de código:

SUB r3 , r4 -> r10 ; Escribe r3 - r4 en r10 Y r10 , r3 -> r11 ; Escribe r10 y r3 en r11        

Las etapas de búsqueda y decodificación de instrucciones envían la segunda instrucción un ciclo después de la primera. Se transmiten por el conducto como se muestra en este diagrama:

En una cadena de montaje ingenua , sin consideración de riesgos, el riesgo de los datos progresa de la siguiente manera:

En el ciclo 3, la SUBinstrucción calcula el nuevo valor para r10. En el mismo ciclo, ANDse decodifica la operación y r10se obtiene el valor de del archivo de registros. Sin embargo, la SUBinstrucción aún no ha escrito su resultado en r10. La reescritura de esto normalmente ocurre en el ciclo 5 (recuadro verde). Por lo tanto, el valor leído del archivo de registros y pasado a la ALU (en la etapa de ejecución de la ANDoperación, recuadro rojo) es incorrecto.

En lugar de ello, debemos pasar los datos que se calcularon de SUBnuevo a la etapa de ejecución (es decir, al círculo rojo del diagrama) de la ANDoperación antes de que se escriban de nuevo normalmente. La solución a este problema es un par de multiplexores de derivación. Estos multiplexores se ubican al final de la etapa de decodificación y sus salidas en flop son las entradas a la ALU. Cada multiplexor selecciona entre:

  1. Un puerto de lectura de archivo de registro (es decir, la salida de la etapa de decodificación, como en la tubería ingenua): flecha roja
  2. La tubería de registro actual de la ALU (para omitirla en una etapa): flecha azul
  3. El canal de registro actual de la etapa de acceso (que es un valor cargado o un resultado de ALU reenviado, esto permite omitir dos etapas): flecha violeta . Tenga en cuenta que esto requiere que los datos se transmitan hacia atrás en el tiempo un ciclo. Si esto ocurre, se debe insertar una burbujaAND para detener la operación hasta que los datos estén listos.

La lógica de la etapa de decodificación compara los registros escritos por las instrucciones en las etapas de ejecución y acceso de la canalización con los registros leídos por la instrucción en la etapa de decodificación, y hace que los multiplexores seleccionen los datos más recientes. Estos multiplexores de derivación permiten que la canalización ejecute instrucciones simples con solo la latencia de la ALU, el multiplexor y un flip-flop. Sin los multiplexores, la latencia de escritura y posterior lectura del archivo de registros tendría que incluirse en la latencia de estas instrucciones.

Tenga en cuenta que los datos solo se pueden pasar hacia adelante en el tiempo; no se pueden volver a una etapa anterior si aún no se han procesado. En el caso anterior, los datos se pasan hacia adelante (cuando el ANDestá listo para el registro en la ALU, el SUBya lo ha calculado).

Solución B. Interbloqueo de tuberías

Sin embargo, tenga en cuenta las siguientes instrucciones:

LD adr -> r10 Y r10 , r3 -> r11      

Los datos leídos de la dirección adrno están presentes en la caché de datos hasta después de la etapa de acceso a la memoria de la LDinstrucción. En ese momento, la ANDinstrucción ya ha pasado por la ALU. Para resolver esto, sería necesario que los datos de la memoria se pasaran hacia atrás en el tiempo hasta la entrada a la ALU. Esto no es posible. La solución es retrasar la ANDinstrucción un ciclo. El peligro de los datos se detecta en la etapa de decodificación y las etapas de búsqueda y decodificación se detienen : se les impide cambiar sus entradas y, por lo tanto, permanecen en el mismo estado durante un ciclo. Las etapas de ejecución, acceso y reescritura posteriores ven una instrucción de no operación (NOP) adicional insertada entre las instrucciones LDy AND.

Este NOP se denomina burbuja de tubería , ya que flota en la tubería, como una burbuja de aire en una tubería de agua, ocupando recursos pero sin producir resultados útiles. El hardware para detectar un peligro de datos y detener la tubería hasta que se elimine el peligro se denomina interbloqueo de tubería .

Pasando atrás en el tiempoProblema resuelto usando una burbuja

Sin embargo, no es necesario utilizar un enclavamiento de canalización con ningún reenvío de datos. El primer ejemplo de SUBseguido por ANDy el segundo ejemplo de LDseguido por ANDse pueden resolver deteniendo la primera etapa durante tres ciclos hasta que se logre la reescritura y los datos en el archivo de registro sean correctos, lo que hace que la ANDetapa de decodificación de obtenga el valor de registro correcto. Esto causa un gran impacto en el rendimiento, ya que el procesador pasa mucho tiempo sin procesar nada, pero las velocidades de reloj se pueden aumentar ya que hay menos lógica de reenvío que esperar.

Este riesgo de datos se puede detectar con bastante facilidad cuando el compilador escribe el código de máquina del programa. La máquina Stanford MIPS dependía del compilador para agregar las instrucciones NOP en este caso, en lugar de tener los circuitos para detectar y (lo que es más complicado) bloquear las dos primeras etapas de la cadena de bloques. De ahí el nombre MIPS: Microprocessor without Interlocked Pipeline Stages (Microprocesador sin etapas de cadena de bloques interconectadas). Resultó que las instrucciones NOP adicionales agregadas por el compilador expandieron los binarios del programa lo suficiente como para que se redujera la tasa de aciertos de la caché de instrucciones. El hardware de bloqueo, aunque caro, se volvió a incluir en diseños posteriores para mejorar la tasa de aciertos de la caché de instrucciones, momento en el que el acrónimo ya no tenía sentido.

Controlar los peligros

Los riesgos de control son causados ​​por ramificaciones condicionales e incondicionales. La secuencia de comandos RISC clásica resuelve las ramificaciones en la etapa de decodificación, lo que significa que la recurrencia de resolución de la ramificación tiene una duración de dos ciclos. Hay tres implicaciones:

  • La recurrencia de resolución de bifurcación pasa por una gran cantidad de circuitos: la lectura de caché de instrucciones, la lectura de archivo de registro, el cálculo de la condición de bifurcación (que implica una comparación de 32 bits en las CPU MIPS) y el siguiente multiplexor de dirección de instrucción.
  • Debido a que los objetivos de bifurcación y salto se calculan en paralelo a la lectura del registro, las ISA RISC normalmente no tienen instrucciones que se ramifiquen a una dirección de registro + desplazamiento. Se admite el salto a registro.
  • En cualquier rama tomada, la instrucción inmediatamente posterior a la rama siempre se obtiene de la caché de instrucciones. Si se ignora esta instrucción, hay una penalización de IPC de un ciclo por rama tomada , que es lo suficientemente grande.

Hay cuatro esquemas para resolver este problema de rendimiento con ramas:

  • Predicción de no ejecución: siempre se obtiene la instrucción después de la bifurcación desde la caché de instrucciones, pero solo se ejecuta si no se ha realizado la bifurcación. Si no se ha realizado la bifurcación, la secuencia permanece llena. Si se ha realizado la bifurcación, la instrucción se elimina (se marca como si fuera una NOP) y se pierde la oportunidad de un ciclo para finalizar una instrucción.
  • Ramificación probable: siempre se obtiene la instrucción después de la ramificación desde la caché de instrucciones, pero solo se ejecuta si se tomó la ramificación. El compilador siempre puede llenar el espacio de demora de ramificación en una ramificación de este tipo y, dado que las ramificaciones se toman con más frecuencia que las que no, dichas ramificaciones tienen una penalización de IPC menor que el tipo anterior.
  • Ranura de retardo de bifurcación : según el diseño de la bifurcación retrasada y las condiciones de la bifurcación, se determina si la instrucción que sigue inmediatamente a la instrucción de bifurcación se ejecuta incluso si se realiza la bifurcación. En lugar de aplicar una penalización de IPC por una fracción de bifurcaciones realizadas (quizás el 60 %) o no realizadas (quizás el 40 %), las ranuras de retardo de bifurcación aplican una penalización de IPC por aquellas bifurcaciones en las que el compilador no pudo programar la ranura de retardo de bifurcación. Los diseñadores de SPARC, MIPS y MC88K diseñaron una ranura de retardo de bifurcación en sus ISA.
  • Predicción de bifurcación : en paralelo con la obtención de cada instrucción, se adivina si la instrucción es una bifurcación o un salto y, de ser así, se adivina el objetivo. En el ciclo posterior a una bifurcación o un salto, se obtiene la instrucción en el objetivo adivinado. Si la suposición es incorrecta, se elimina el objetivo obtenido incorrectamente.

Las ramificaciones retrasadas fueron controvertidas, en primer lugar, porque su semántica es complicada. Una ramificación retrasada especifica que el salto a una nueva ubicación ocurre después de la siguiente instrucción. Esa siguiente instrucción es la que inevitablemente carga la caché de instrucciones después de la ramificación.

Las ramas retrasadas han sido criticadas [¿ por quién? ] como una mala elección a corto plazo en el diseño de ISA:

  • Los compiladores generalmente tienen algunas dificultades para encontrar instrucciones lógicamente independientes para colocar después de la bifurcación (la instrucción después de la bifurcación se llama ranura de retardo), por lo que deben insertar NOP en las ranuras de retardo.
  • Los procesadores superescalares , que obtienen múltiples instrucciones por ciclo y deben tener alguna forma de predicción de saltos, no se benefician de los saltos retrasados. La ISA Alpha omitió los saltos retrasados, ya que estaba pensada para procesadores superescalares.
  • El inconveniente más grave de las bifurcaciones retrasadas es la complejidad de control adicional que conllevan. Si la instrucción de ranura de retraso toma una excepción, el procesador debe reiniciarse en la bifurcación, en lugar de en la siguiente instrucción. Las excepciones tienen esencialmente dos direcciones, la dirección de excepción y la dirección de reinicio, y generar y distinguir entre las dos correctamente en todos los casos ha sido una fuente de errores para los diseños posteriores.

Excepciones

Supongamos que un RISC de 32 bits procesa una instrucción ADD que suma dos números grandes y el resultado no cabe en 32 bits.

La solución más simple, que ofrecen la mayoría de las arquitecturas, es la aritmética envolvente. A los números mayores que el valor codificado máximo posible se les quitan los bits más significativos hasta que quepan. En el sistema de números enteros habitual, 3000000000+30000000000=6000000000. Con la aritmética envolvente de 32 bits sin signo, 3000000000+30000000000=1705032704 (6000000000 mod 2^32). Esto puede no parecer demasiado útil. El mayor beneficio de la aritmética envolvente es que cada operación tiene un resultado bien definido.

Pero el programador, especialmente si programa en un lenguaje que admita números enteros grandes (por ejemplo, Lisp o Scheme ), puede no querer encapsular la aritmética. Algunas arquitecturas (por ejemplo, MIPS) definen operaciones de adición especiales que se ramifican a ubicaciones especiales en caso de desbordamiento, en lugar de encapsular el resultado. El software en la ubicación de destino es responsable de solucionar el problema. Esta ramificación especial se denomina excepción. Las excepciones se diferencian de las ramificaciones regulares en que la dirección de destino no está especificada por la propia instrucción, y la decisión de ramificación depende del resultado de la instrucción.

El tipo más común de excepción visible por software en una de las máquinas RISC clásicas es una falla de TLB .

Las excepciones son diferentes de las ramificaciones y saltos, porque esos otros cambios en el flujo de control se resuelven en la etapa de decodificación. Las excepciones se resuelven en la etapa de reescritura. Cuando se detecta una excepción, las siguientes instrucciones (anteriores en la tubería) se marcan como no válidas y, a medida que fluyen hacia el final de la tubería, sus resultados se descartan. El contador del programa se establece en la dirección de un controlador de excepciones especial y se escriben registros especiales con la ubicación y la causa de la excepción.

Para que sea fácil (y rápido) para el software solucionar el problema y reiniciar el programa, la CPU debe tomar una excepción precisa. Una excepción precisa significa que se han ejecutado todas las instrucciones hasta la instrucción de excepción, y que la instrucción de excepción y todo lo que sigue no se ha ejecutado.

Para tomar excepciones precisas, la CPU debe confirmar los cambios en el estado visible del software en el orden del programa. Esta confirmación en orden ocurre de manera muy natural en la secuencia clásica de RISC. La mayoría de las instrucciones escriben sus resultados en el archivo de registros en la etapa de reescritura, por lo que esas escrituras ocurren automáticamente en el orden del programa. Sin embargo, las instrucciones de almacenamiento escriben sus resultados en la cola de datos de almacenamiento en la etapa de acceso. Si la instrucción de almacenamiento toma una excepción, la entrada de la cola de datos de almacenamiento se invalida para que no se escriba en la memoria SRAM de datos de caché más tarde.

Manejo de errores de caché

Ocasionalmente, la caché de datos o de instrucciones no contiene un dato o una instrucción requeridos. En estos casos, la CPU debe suspender la operación hasta que la caché se pueda llenar con los datos necesarios y luego debe reanudar la ejecución. El problema de llenar la caché con los datos requeridos (y potencialmente volver a escribir en la memoria la línea de caché expulsada) no es específico de la organización de la canalización y no se analiza aquí.

Existen dos estrategias para manejar el problema de suspensión/reanudación. La primera es una señal de bloqueo global. Esta señal, cuando se activa, impide que las instrucciones avancen por el pipeline, generalmente desactivando el reloj de los flip-flops al comienzo de cada etapa. La desventaja de esta estrategia es que hay una gran cantidad de flip-flops, por lo que la señal de bloqueo global tarda mucho tiempo en propagarse. Dado que la máquina generalmente tiene que bloquearse en el mismo ciclo en el que identifica la condición que requiere el bloqueo, la señal de bloqueo se convierte en una ruta crítica que limita la velocidad.

Otra estrategia para manejar la suspensión/reanudación es reutilizar la lógica de excepción. La máquina toma una excepción en la instrucción infractora y todas las demás instrucciones se invalidan. Cuando la caché se ha llenado con los datos necesarios, la instrucción que causó la falla de caché se reinicia. Para acelerar el manejo de la falla de caché de datos, la instrucción se puede reiniciar de modo que su ciclo de acceso ocurra un ciclo después de que se llene la caché de datos.

Véase también

Referencias

  1. ^ Patterson, David (12 de mayo de 1981). "RISC I: Un computador VLSI con conjunto de instrucciones reducido". Isca '81. págs. 443–457.
  2. ^ Patterson, David (12 de mayo de 1981). "RISC I: Un computador VLSI con conjunto de instrucciones reducido". Isca '81. págs. 443–457.
  • Hennessy, John L.; Patterson, David A. (2011). Arquitectura informática: un enfoque cuantitativo (5.ª ed.). Morgan Kaufmann. ISBN 978-0123838728.
Obtenido de "https://es.wikipedia.org/w/index.php?title=Pipeline_RISC_clásica&oldid=1191069658"