stringtranslate.com

Tubería RISC clásica

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

Cada uno de estos diseños escalares clásicos de RISC busca e intenta ejecutar una instrucción por ciclo . El principal concepto común de cada diseño es un canal de instrucciones de ejecución de cinco etapas . Durante la operación, cada etapa de la tubería funciona con 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 canal RISC de cinco etapas

Canalización básica de cinco etapas en una máquina RISC (IF = obtención de instrucciones , ID = decodificación de instrucciones, EX = ejecución, MEM = acceso a memoria, WB = escritura de registro). El eje vertical son instrucciones sucesivas; el eje horizontal es el tiempo. Entonces, en la columna verde, la instrucción más antigua está en la etapa WB y la instrucción más reciente está en proceso de búsqueda de instrucciones.

búsqueda de instrucciones

Las instrucciones residen en una memoria que tarda un ciclo en leerse. Esta memoria puede estar dedicada a SRAM o a una caché de instrucciones . El término "latencia" se utiliza a menudo en informática y significa el tiempo desde que comienza una operación hasta que se completa. Por lo tanto, la recuperación de instrucciones tiene una latencia de un ciclo de reloj (si se utiliza SRAM de ciclo único o si la instrucción estaba en la memoria caché). Por lo tanto, durante la etapa de búsqueda de instrucciones , se recupera 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 la siguiente PC. La siguiente PC se calcula incrementando la PC en 4 y eligiendo si tomarla como la siguiente PC o tomar el resultado de un cálculo de bifurcación/salto como la siguiente 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 rama, un salto o una excepción (consulte ramas retrasadas , a continuación). ). (Tenga en cuenta que algunas máquinas modernas utilizan algoritmos más complicados ( predicción de rama y predicción de objetivo de rama ) para adivinar la siguiente dirección de instrucción).

decodificación de instrucciones

Otra cosa que separa a las primeras máquinas RISC de las anteriores máquinas CISC es que RISC no tiene microcódigo . [2] En el caso de las instrucciones microcodificadas CISC, una vez obtenidas del caché de instrucciones, los bits de instrucción se desplazan hacia abajo en la canalización, donde la lógica combinacional simple en cada etapa de la canalización 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 denominada 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 índices de registros.

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 los índices se presentan en la memoria de registros, como la dirección. De este modo, los dos registros nombrados se leen del archivo de registro . En el diseño MIPS, el archivo de registro tenía 32 entradas.

Al mismo tiempo que se lee el archivo de registro, la lógica de emisión de instrucciones en esta etapa determina si la canalización está lista para ejecutar la instrucción en esta etapa. De lo contrario, la lógica del problema hace que tanto la etapa de obtención de instrucciones como la etapa de decodificación se detengan. En un ciclo de pérdida, 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 salto se calcula en paralelo con la lectura del archivo de registro. La condición de bifurcación se calcula en el siguiente ciclo (después de leer el archivo de registro), y si se toma la bifurcación o si la instrucción es un salto, a la PC en la primera etapa se le asigna el destino de la bifurcación, en lugar de la PC incremental que ha sido calculado. Algunas arquitecturas utilizaron la unidad lógica aritmética (ALU) en la etapa de ejecución, a costa de un rendimiento de instrucciones ligeramente menor.

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

Ejecutar

La etapa de Ejecución es donde ocurre el cálculo real. Normalmente, esta etapa consta de una ALU y también de una pequeña palanca de cambios. También puede incluir un multiplicador y divisor de ciclos múltiples.

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

El cambiador de brocas es responsable de los cambios y las rotaciones.

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

Acceso a la memoria

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

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

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

Respóndeme

Durante esta etapa, tanto las instrucciones de ciclo único como las de dos ciclos escriben sus resultados en el archivo de registro. Tenga en cuenta que dos etapas diferentes acceden al archivo de registro 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 más abajo para obtener más información sobre los peligros). Esto se debe a que uno de los registros de origen que se lee 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 registro 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 peligro para situaciones en las que las instrucciones en una tubería producirían respuestas incorrectas.

Peligros estructurales

Los peligros estructurales ocurren cuando dos instrucciones pueden intentar utilizar los mismos recursos al mismo tiempo. Las canalizaciones RISC clásicas evitaron estos peligros replicando hardware. En particular, las instrucciones de bifurcación podrían haber utilizado la ALU para calcular la dirección de destino de la bifurcación. Si la ALU se usara en la etapa de decodificación para ese propósito, una instrucción de ALU seguida de una bifurcación habría visto que ambas instrucciones intentaran usar la ALU simultáneamente. Es sencillo resolver este conflicto diseñando un sumador de destino de rama especializado en la etapa de decodificación.

Peligros de datos

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

En el canal RISC clásico, los peligros de los datos se evitan de dos maneras:

Solución A. Omitir

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

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

SUB r3 , r4 -> r10 ; Escribe r3 - r4 en r10 AND 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. Fluyen por la tubería como se muestra en este diagrama:

En una tubería ingenua , sin consideración de peligros, los peligros de los datos progresan de la siguiente manera:

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

En su lugar, debemos pasar los datos que fueron calculados SUBa la etapa de Ejecución (es decir, al círculo rojo en el diagrama) de la ANDoperación antes de que normalmente se reescriban. La solución a este problema es un par de multiplexores de derivación. Estos multiplexores se encuentran al final de la etapa de decodificación y sus salidas fallidas 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 canalización ingenua): flecha roja
  2. La tubería de registro actual de la ALU (para omitir en una etapa): flecha azul
  3. La canalización 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 morada . Tenga en cuenta que esto requiere que los datos retrocedan 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 hacen posible que la tubería ejecute instrucciones simples con solo la latencia de la ALU, el multiplexor y un flip-flop. Sin los multiplexores, la latencia de escribir y luego leer el archivo de registro tendría que incluirse en la latencia de estas instrucciones.

Tenga en cuenta que los datos solo se pueden transmitir en el tiempo; los datos no se pueden omitir a una etapa anterior si aún no se han procesado. En el caso anterior, los datos se pasan hacia adelante (cuando está ANDlisto para el registro en la ALU, ya SUBlos ha calculado).

Solución B. Bloqueo de tuberías

Sin embargo, considere las siguientes instrucciones:

Dirección LD -> 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 este momento, la ANDinstrucción ya ha pasado por la ALU. Para resolver esto sería necesario que los datos de la memoria se pasen hacia atrás en el tiempo hasta la entrada de 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 recuperación y decodificación se detiene : 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 porque 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 en los datos y detener la tubería hasta que se elimine el peligro se denomina enclavamiento de tubería .

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

Este peligro en los datos se puede detectar con bastante facilidad cuando el compilador escribe el código de máquina del programa. La máquina MIPS de Stanford se basó en el compilador para agregar las instrucciones NOP en este caso, en lugar de tener los circuitos para detectar y (lo que es más complicado) detener las dos primeras etapas del proceso. De ahí el nombre MIPS: Microprocesador sin etapas de tubería interbloqueadas. Resultó que las instrucciones NOP adicionales agregadas por el compilador expandieron los binarios del programa lo suficiente como para reducir la tasa de aciertos de la caché de instrucciones. El hardware de bloqueo, aunque costoso, se volvió a colocar 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 peligros de control son causados ​​por ramificaciones condicionales e incondicionales. La canalización RISC clásica resuelve bifurcaciones en la etapa de decodificación, lo que significa que la recurrencia de la resolución de bifurcaciones tiene una duración de dos ciclos. Hay tres implicaciones:

Existen cuatro esquemas para solucionar este problema de rendimiento con las sucursales:

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

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

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 sencilla, proporcionada por 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 cortan los bits más significativos hasta que encajen. En el sistema de números enteros habitual, 3000000000+3000000000=6000000000. Con aritmética envolvente de 32 bits sin signo, 3000000000+3000000000=1705032704 (6000000000 mod 2^32). Puede que esto no parezca muy ú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 soporta números enteros grandes (por ejemplo, Lisp o Scheme ), puede no querer aritmética envolvente. Algunas arquitecturas (por ejemplo, MIPS) definen operaciones de suma especiales que se ramifican a ubicaciones especiales en caso de desbordamiento, en lugar de ajustar el resultado. El software en la ubicación de destino es responsable de solucionar el problema. Esta rama especial se llama excepción. Las excepciones se diferencian de las bifurcaciones normales en que la dirección de destino no la especifica la instrucción misma y la decisión de bifurcar 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 TLB .

Las excepciones son diferentes de las bifurcaciones y los 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 hasta 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 al software le resulte fácil (y rápido) solucionar el problema y reiniciar el programa, la CPU debe realizar una excepción precisa. Una excepción precisa significa que se han ejecutado todas las instrucciones hasta la instrucción de excepción, y la instrucción de excepción y todo lo posterior no se han ejecutado.

Para hacer excepciones precisas, la CPU debe confirmar cambios en el estado visible del software en el orden del programa. Esta confirmación en orden ocurre de forma muy natural en el canal RISC clásico. La mayoría de las instrucciones escriben sus resultados en el archivo de registro en la etapa de reescritura, por lo que esas escrituras ocurren automáticamente en el orden del programa. Las instrucciones de la tienda, sin embargo, escriben sus resultados en la cola de datos de la tienda en la etapa de acceso. Si la instrucción de almacenamiento realiza una excepción, la entrada de la cola de datos de almacenamiento se invalida para que no se escriba en la SRAM de datos de caché más adelante.

Manejo de fallas de caché

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

Hay dos estrategias para manejar el problema de suspender/reanudar. La primera es una señal de pérdida global. Esta señal, cuando se activa, evita que las instrucciones avancen por la tubería, generalmente desconectando 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 pérdida global tarda mucho en propagarse. Dado que la máquina generalmente tiene que detenerse en el mismo ciclo en el que identifica la condición que requiere la pérdida, la señal de pérdida se convierte en una ruta crítica limitadora de velocidad.

Otra estrategia para manejar la suspensión/reanudación es reutilizar la lógica de excepción. La máquina hace una excepción con la instrucción infractora y todas las instrucciones adicionales quedan invalidadas. Cuando la memoria caché se ha llenado con los datos necesarios, se reinicia la instrucción que provocó la falta de memoria caché. Para acelerar el manejo de errores de caché de datos, la instrucción se puede reiniciar para que su ciclo de acceso ocurra un ciclo después de que se llene el caché de datos.

Ver también

Referencias

  1. ^ Patterson, David (12 de mayo de 1981). "RISC I: una computadora VLSI con conjunto de instrucciones reducido". Isca'81. págs. 443–457.
  2. ^ Patterson, David (12 de mayo de 1981). "RISC I: una computadora VLSI con conjunto de instrucciones reducido". Isca'81. págs. 443–457.