Está en la página 1de 57

En este capítulo vamos a ver cómo mejorar las prestaciones de la CPU mediante los

procesadores segmentados (o en pipeline), los cuales incorporan una técnica para acelerar el
ritmo de ejecución de las instrucciones.
En primer lugar empezaremos por comentar algunos aspectos básicos para introducir los
conceptos en los que se apoya esta técnica.
A continuación nos centraremos en nuestro procesador de referencia, el MIPS64, viendo la
configuración de las etapas que componen su cauce.
Como veremos, hay diversos factores que pueden impedir un aprovechamiento óptimo del
concepto de pipeline en la CPU. Trataremos estos factores y las técnicas para evitarlos en la
medida de lo posible.
Por último abordaremos una mejora más del pipeline mediante el concepto de operaciones
multiciclo que reducirán las esperas o paradas generadas por las instrucciones pesadas, como
las multiplicaciones, divisiones o las operaciones en coma flotante.

Arquitectura de Computadores Segmentación del Cauce - 1

La primera opción que se nos ocurre para aumentar la velocidad de un procesador es aumentar la
velocidad del reloj, lo cual es muy fácil, pero claro, si los circuitos que componen las etapas de
ejecución del procesador no soportan esa velocidad, éste se quema o deja de funcionar
correctamente.
Así, para poder aumentar la velocidad del reloj, primero se deben hacer más rápidos los circuitos
con los que se construyen los procesadores y la memoria principal. No obstante, se debe
considerar el coste que supone una mejora, y que el límite de esta velocidad lo impone el estado
del arte actual de la tecnología.
Otra posibilidad es organizar el hardware para poder ejecutar más de una instrucción
simultáneamente: concurrencia. La concurrencia se puede obtener en dos niveles: al nivel del
procesador y al nivel de la instrucción. La concurrencia al nivel de la CPU se obtiene disponiendo
de múltiples procesadores ejecutando simultáneamente varias instrucciones. Obtener
concurrencia a nivel de la instrucción significa poder ejecutar varias instrucciones
simultáneamente con una única CPU. Este último tipo de paralelismo se denomina segmentación,
aunque suele ser más conocido por su denominación en inglés: pipelining.
Las arquitecturas con múltiples procesadores suelen utilizarse en máquinas de muy altas
prestaciones (y muy alto precio). Sin embargo, con arquitecturas segmentadas se consigue una
muy buena mejora del rendimiento y a un coste asequible. Por esto, es normal que todos los
microprocesadores actuales de propósito general incorporen el pipelining. Ya que es muy común
su utilización en los actuales procesadores, vamos a abordar aquí esta técnica del pipelining,
mientras que las arquitecturas multiprocesador las dejaremos para asignaturas o textos de
arquitecturas paralelas o avanzadas.

Arquitectura de Computadores Segmentación del Cauce - 2

Ahora ya podemos abordar el concepto de pipeline. El proceso en pipeline (o segmentado) es
similar al utilizado en cualquier cadena de montaje, y el nombre pipeline (tubería) se debe al
hecho de que, como en una tubería, en la entrada se aceptan nuevos elementos (instrucciones)
antes de que los previamente aceptados salgan por la salida.
Empecemos con el ejemplo de una cadena de montaje. Supongamos una gran pastelería en la
que las tartas primero se hacen en el horno y después se empaquetan para la venta. El proceso
de empaquetar una tarta consiste en:
1. Poner una caja vacía en la mesa.
2. Meter una tarta en la caja.
3. Cerrar y precintar la caja.
4. Poner una etiqueta en la caja.
5. Llevar la caja a un gran contenedor.
Si cada una de estas operaciones la realiza un operario en 10 segundos, parece claro que se
tarda 50 s en empaquetar una tarta y, por lo tanto, en empaquetar 10 tartas se tardaría 500 s.

Arquitectura de Computadores Segmentación del Cauce - 3

Ahora supongamos que se dispone de una cadena de empaquetado de tartas con una cinta
transportadora sobre la que trabajan cinco operarios especializados en tareas distintas. El primer
operario pone la caja-1 en la cinta transportadora, y ésta avanza hasta que la caja-1 está donde el
segundo operario, que introduce una tarta dentro de la caja-1, al mismo tiempo que el primer
operario pone otra caja-2 en la cinta. La caja-1 sigue avanzando hasta el tercer operario, que la
cierra y la precinta, al mismo tiempo que el segundo operario mete otra tarta en la caja-2 y el
primer operario pone otra caja-3 en la cinta. La caja-1 sigue su camino en la cinta pasando por el
cuarto operario, que pone una etiqueta, hasta llegar al quinto operario, que la retira de la cinta.
En el momento que el quinto operario retira la caja de la cinta, hay cuatro cajas más en la cinta. Si
cada una de estas fases de empaquetado se realiza en 10 s, a partir de ahora, cada 10 s saldrá
una nueva tarta empaquetada, en lugar de hacerlo cada 50 s que se tardaba cuando no había
cadena de empaquetado. A partir de ahora, solamente se tardará100 segundos en tener 10 tartas
empaquetadas, mientras que en el caso de cuando se tenía un solo operario se tardaba 500
segundos.
Debe quedar claro que aunque ahora sale una nueva tarta empaquetada cada 10 s, la
preparación completa de cada tarta sigue requiriendo 50 s (igual que cuando había una sola
persona preparando las tartas).
Ha aumentado el rendimiento, pero se mantiene el tiempo de empaquetado de cada tarta.
Si calculamos el rendimiento de los dos sistemas de empaquetado de tartas, veremos que el
rendimiento en este último caso se ha multiplicado por 5 (¡igual al número de etapas!).

Arquitectura de Computadores Segmentación del Cauce - 4

Según lo que acabamos de ver, parece que interesa dividir las fases de ejecución de las
instrucciones en más etapas, para así obtener un mayor rendimiento en la ejecución.
La ejecución de una instrucción podría descomponerse en las siguientes 5 etapas:
1. F: Alimentación de la instrucción (fetch)
2. D: Decodificación de la instrucción / Lectura de registros
3. E: Ejecución (en la ALU) / Cálculo de la dirección efectiva
4. M: Acceso a memoria
5. W: Escritura del resultado en registros de la CPU
Si ahora la ejecución de una instrucción está descompuesta en 5 etapas, cada etapa puede durar
aproximadamente 1/5 de la duración total de la ejecución de la instrucción. Si suponemos que la
duración de un ciclo de reloj es igual a la duración de cada una de estas pequeñas etapas,
podemos decir, en principio, que con la técnica de la segmentación (o pipelining) se consigue que
a cada ciclo de reloj finalice una instrucción, o lo que es lo mismo, una velocidad de instrucción
por ciclo.
Debemos tener en cuenta que:
• Cada etapa dispone de los recursos hardware necesarios para realizar su cometido.
• Las ejecuciones de las instrucciones se solapan.
• Todas las etapas tienen la misma duración (ciclo de reloj).
• La duración del ciclo de reloj lo fija la etapa más lenta.

Arquitectura de Computadores Segmentación del Cauce - 5

que tarda 5 ciclos. y hasta que no termina. en el que supondremos que el ciclo de reloj es 1 ns. De esta manera.En este histograma podemos ver la comparación entre dos procesadores de similares características y que su gran diferencia consiste en estar o no estar segmentados. cuando la primera instrucción termina. En cambio. al ciclo siguiente se arranca la siguiente instrucción y. no comienza la ejecución de otra instrucción. por lo que termina una instrucción cada 5 ciclos. de 5 instrucciones cada 5 ciclos. consiguiente un rendimiento de una instrucción por ciclo o. que se consigue un rendimiento de 1 instrucción cada 5 ciclos. al ciclo siguiente termina la segunda. El ciclo de reloj es igual para ambos casos (1 ns). tenemos que a cada ciclo finaliza una instrucción. cuando una instrucción arranca. Utilizaremos el procesador del ejemplo que hemos visto en la página anterior. ya que partimos de dos procesadores con similares características. el procesador no segmentado ejecuta una instrucción. Arquitectura de Computadores Segmentación del Cauce . como vemos en el gráfico. de esta manera. o sea. El tiempo de ejecución de la instrucción (si todas las instrucciones pasan por todas las etapas) también es igual en ambos casos (5 ciclos). en el caso del procesador segmentado.6 . En cuanto al rendimiento.

en un momento dado hay tantas instrucciones en ejecución como etapas tiene. no obstante. la aceleración o speed up. es el cociente entre el tiempo medio que transcurre entre la finalización de las instrucciones en el procesador no segmentado y en el segmentado. No debemos olvidar que en un procesador segmentado (una vez que está lleno el cauce y en condiciones ideales).Como habíamos visto anteriormente. consiguiendo un número medio de ciclos por instrucción (CPI) igual a 1. a cada ciclo finaliza la ejecución de una instrucción. cada etapa se está ocupando de una función distinta de cada instrucción. en condiciones ideales. En el procesador segmentado.7 . Arquitectura de Computadores Segmentación del Cauce .

El tiempo medio de ejecución de una instrucción en el procesador NO segmentado se obtiene mediante la suma de los tiempos de ejecución de cada tipo de instrucción por sus frecuencias de aparición en los programas. consiguiendo así. obteniendo así.Veamos la mejora de aceleración que se experimenta al segmentar un procesador convencional.6.6 veces más rápido que el convencional. pero. De esta manera. una mejora del 4. Así tenemos que cada instrucción tardará en ejecutarse un total de 5 ns. la mejora en rendimiento (speed up) que se experimenta es el cociente entre el tiempo medio que transcurre entre la finalización de las instrucciones en el procesador no segmentado y el segmentado. tenemos que cada etapa requiere 1 ciclo de reloj (1 ns). El procesador segmentado consta de 5 etapas. mientras que las de salto y acceso a memoria consumen 5 ciclos de reloj. Esto significa que. Arquitectura de Computadores Segmentación del Cauce . Las instrucciones aritméticas del procesador no segmentado requieren 4 ciclos. un 20% de instrucciones de salto y otro 40% de instrucciones de acceso a operandos en memoria principal. para programas con esta distribución de frecuencias en sus instrucciones.6 ns. un valor medio de 4. y el ciclo de reloj es 1 ns. En el caso del procesador segmentado.8 . en realidad. cuando ejecuta un programa que consta del 40% de instrucciones aritméticas. cada 1 ns finalizará una instrucción. el procesador segmentado es 4.

9 .Arquitectura de Computadores Segmentación del Cauce .

10 . El tiempo de ejecución de cada etapa va a ser un ciclo. vamos a concretarlo en una versión simplificada de la arquitectura MIPS64.Una vez vistos los conceptos básicos del pipeline. Arquitectura de Computadores Segmentación del Cauce . Ahora iremos mostrando en las siguientes páginas la descripción de cada una de las 5 etapas de este pipeline simplificado de MIPS64. en la que la Unidad Aritmético-Lógica solamente va a operar con datos enteros. Vamos a considerar una versión básica de 5 etapas.

todas las instrucciones son de longitud constante. La dirección calculada se lleva al registro PC. La instrucción queda en el registro IR de donde se irá extrayendo información en las sucesivas etapas.11 . Arquitectura de Computadores Segmentación del Cauce . de la dirección indicada en el registro Contador de Programa PC (Program Counter). A continuación se calcula la dirección de la siguiente instrucción en secuencia (su dirección en memoria). En nuestro caso. añadiéndole al PC el tamaño de la instrucción alimentada. y se almacena en el registro de instrucción IR (Instruction Register).En esta primera etapa se extrae o alimenta una instrucción de memoria. 4 bytes.

por lo que si la operación no requiere alguno de los registros leídos. se le hace una extensión de signo a 32 bits y se guarda en el registro Inm. La salida de este multiplexor proporciona la dirección de la siguiente instrucción que se va a ejecutar. •  Si la instrucción es de bifurcación. (En la instrucción de salto. algunas de estas acciones no tenga sentido realizarlas. En cualquier caso. •  Si la instrucción contiene un campo de 16 bits con un valor inmediato. o bien la de la dirección indicada en la instrucción de salto. simplemente no se utiliza. y el resultado de la comparación se dirige a la entrada de control del multiplexor de la etapa de Fetch. Arquitectura de Computadores Segmentación del Cauce . ya que estas acciones se realizan en paralelo. o sea. es decir. la ALU hace dos cosas: o  Primero añade al PC el desplazamiento correspondiente al valor inmediato que se indica en la instrucción de salto (desplazado 2 bits a la izquierda. multiplicado por 4) llevando el resultado a la entrada del multiplexor de la etapa F. pues como todas las instrucciones ocupan 4 bytes. y se guardan en los registros temporales A y B. según la operación a realizar. al mismo tiempo que la decodificación. el desplazamiento del salto se indica como un múltiplo de 4. el valor inmediato o la dirección de salto calculada. •  En paralelo se lee el contenido de los registros indicados como operandos en la instrucción. siempre están en una dirección múltiplo de 4).12 . bien la siguiente en secuencia (esto ya lo habrá hecho en el ciclo anterior). se averigua cuál es la operación que se debe realizar. no se pierde tiempo al hacerlo. o  A continuación se comprueba si el registro A tiene el valor 0. Es posible que.Aquí se realizan 4 funciones: •  Decodificación de la instrucción alimentada.

donde se realiza una de estas tres posibles funciones. La ALU realiza la operación indicada por el código de función u operación. El resultado se deja en el registro temporal ALUoutput. utilizando los valores de los registros temporales A y B.Esta es la etapa de la Unidad Aritmético-Lógica (ALU). utilizando los valores del registro temporal A y el valor del registro Inm (que contiene el valor inmediato de la instrucción). •  Instrucción registro-Inmediato (A op Inm à ALUoutput). Arquitectura de Computadores Segmentación del Cauce .13 . La ALU suma estos operandos para formar una dirección absoluta de memoria. El resultado se deja en el registro temporal ALUoutput. Estas tres funciones distintas pueden estar en la misma etapa (aunque solo se ejecuta una de ellas en cada instrucción) ya que nunca se requiere que se haga más de una de estas operaciones sobre la misma instrucción. El resultado se deja en el registro ALUoutput. dependiendo del tipo de instrucción: •  Instrucción con registros (A op B à ALUoutput). La ALU realiza la operación indicada por el código de función u operación. •  Referencia a memoria (A+Inm à ALUoutput).

14 . Dependiendo de si se trata de una instrucción de carga o de almacenamiento. Referencia a memoria. el dato del registro temporal B se escribe en memoria. la dirección de memoria utilizada es la calculada en el ciclo (etapa) anterior y que se dejó en ALUoutput. Arquitectura de Computadores Segmentación del Cauce . el dato traído de memoria se deja en el registro temporal LMD. se realiza una de estas acciones: •  Si es una carga. •  Si se trata de un almacenamiento. En cualquier caso.

En esta etapa se escribe un valor en alguno de los registros generales (si la instrucción lo requiere). bien si el valor viene de una posición de memoria (valor en registro temporal LMD) o se trata del resultado de una operación en la ALU.15 . Arquitectura de Computadores Segmentación del Cauce .

  D (Decodificación de Instrucción / Lectura de registros). Si el resultado de la instrucción. desplazamiento… •  Cálculo de dirección efectiva (registro base + desplazamiento). dependiendo del tipo de instrucción. 2. tiene como destino un registro. se realiza en esta fase. aquí tenemos un esquema general de las etapas de MIPS64 1. utilizando para ello el valor del registro leído en la fase D (si es una escritura en memoria) y la dirección de memoria calculada en la fase E. 5.  W (Escritura en registros). En cualquier caso.  E (Ejecución/Cálculo de la dirección efectiva). para que apunte a la dirección de la siguiente instrucción. 3. Aquí.  M (Acceso a memoria). si es un salto o carga/ almacenamiento. lógica. Se extrae una instrucción de la dirección de memoria indicada por el Contador de Programa (PC) y se incrementa éste en 4. o lectura de memoria.16 . para lectura o escritura (carga/almacenamiento). se escribe en éste en esta fase. 4. Se decodifica la instrucción extraída y se lee el contenido de los registros indicados como operandos en la instrucción. Si es una instrucción de salto. Si la instrucción es de acceso a memoria.A modo de resumen. Arquitectura de Computadores Segmentación del Cauce . si es una instrucción aritmética.  F (Alimentación de instrucción – Instruction Fetch). se calcula la dirección de destino incrementando el PC con el desplazamiento indicado en la instrucción. la decodificación se realiza en paralelo con la lectura de los registros. se realiza una de estas funciones: •  Ejecución de una operación en la ALU (Unidad Aritmético-Lógica).

Los registros generales están ubicados en la etapa D. Obsérvese que cuando la instrucción de salto se encuentra en la etapa D. pero su escritura o actualización se produce en otras etapas. Inm. el registro PC está situado en la etapa de extracción de la instrucción (F). Se trata de un pipeline simplificado para la ejecución de estas pocas operaciones: −  Load/Store −  Operaciones con enteros −  Salto condicional "si igual a cero” Como puede verse. B. por lo que solamente se pierde un ciclo en los saltos. Se puede apreciar que algunos registros están ubicados en las etapas en las que se lee su contenido. se salvan en unos registros temporales: IR.En esta figura se muestra el pipeline de la arquitectura de MIPS que se ha comentado en las páginas anteriores. LMD. A. pero se escriben durante la etapa W.17 . sería deseable que en la etapa F se pudiera alimentar ya la siguiente instrucción. en realidad. pero. Con este cauce. al final de cada etapa. Así. y se puede ver cómo fluye una instrucción a través del cauce. se escribe desde la etapa D. la siguiente instrucción se alimenta un ciclo después de la etapa D. los valores obtenidos en ella deben guardarse para poder acceder a ellos desde una etapa posterior. Arquitectura de Computadores Segmentación del Cauce . por ello. ALUoutput.

18 .En la figura de arriba se muestran algunas de las características del pipeline básico de la arquitectura MIPS64. Arquitectura de Computadores Segmentación del Cauce .

Arquitectura de Computadores Segmentación del Cauce .19 .

Por desgracia.20 . Hay tres causas que lo impiden: •  Motivos estructurales. Arquitectura de Computadores Segmentación del Cauce . y que nada retrase el avance de las instrucciones a través del pipeline. no es fácil mantener siempre ocupadas todas las etapas del pipeline.Una vez elegido el número óptimo de etapas. •  Dependencias de operandos. En las siguientes transparencias las comentaremos con cierto detalle. para que el factor de aceleración sea igual al número de etapas se requiere que todas las etapas del pipeline siempre estén llenas de instrucciones útiles. •  Instrucciones de bifurcación.

21 . se tiende a que la ejecución de cada etapa se realice en un ciclo de reloj. el pipeline se para. puede ocurrir que no todas las etapas sean de la misma duración. Por ejemplo. Hay varias causas estructurales (arquitectura del pipeline) que pueden hacer que el pipeline se detenga. Esto hará que la duración efectiva de cada etapa sea igual a la duración de la etapa más larga. por lo que requieren tiempos distintos de CPU. Pues bien.Como ya veremos. el pipeline se detiene hasta que dicha etapa finaliza su trabajo. Pasemos a la siguiente página para tratar este caso con más detalle. si una etapa se detiene para esperar a poder realizar el acceso a memoria. con lo que alguna etapa de corta duración debería esperar a que acabe la siguiente que es más larga. con lo que automáticamente tienden a igualarse los tiempos. Arquitectura de Computadores Segmentación del Cauce . También tenemos que considerar que no todas las instrucciones hacen las mismas cosas. Otra cosa que también puede ocurrir es que desde varias etapas se quiera acceder a memoria simultáneamente (por ejemplo en la etapa de alimentación de instrucción y en la escritura del resultado). cuando una etapa no es capaz de realizar su cometido en un ciclo de reloj. claro. Normalmente los procesadores actuales tienden a un alto número de etapas. Y.

Esto hace que en el 5º ciclo no pueda alimentarse la instrucción I5 por estar ocupada la etapa de extracción de instrucción. en alguna de ellas puede ocurrir que no se realice ningún trabajo. debiendo esperar ésta al ciclo 7 para poder continuar extrayendo instrucciones. la carga de un registro no requerirá dicha última etapa. para algunas instrucciones. mientras que otras pueden necesitar más tiempo para obtener los operandos o escribir el resultado (si están en memoria principal se tarda más que si están en registros). la carga o escritura de un registro requiere menos trabajo de ALU que una división en coma flotante). Obsérvese que como consecuencia del sobretiempo de E2.22 .No todas las instrucciones hacen las mismas cosas y requieren el mismo tiempo de CPU. En el ejemplo de arriba vemos que la instrucción I2 no puede completar la fase de ejecución en el ciclo 4. necesitando para ello también los ciclos 5 y 6. al término de los ciclos 6 y 7 no finaliza ninguna instrucción (lo cual va en perjuicio del rendimiento). No obstante todas las instrucciones pasan por todas las etapas. Puede suceder incluso que alguna de las etapas ni siquiera necesite ejecutarse. Arquitectura de Computadores Segmentación del Cauce . Unas pueden necesitar más tiempo en la etapa de ejecución (por ejemplo. en un procesador cuya última etapa se dedique a escribir en memoria principal. aunque. Por ejemplo.

en las etapas de Fectch y Ejecución puede ser necesario un acceso simultáneo a la ALU para realizar una operación aritmética. como el incremento que debe hacer al PC para actualizarlo (en F) o la suma que se requiere para realizar el cálculo de la dirección efectiva de un operando (en E).Si desde dos etapas se accede a un mismo recurso. Por ejemplo. Por otra parte.23 . también se puede requerir un acceso simultáneo a memoria desde las etapas F y M. Arquitectura de Computadores Segmentación del Cauce . para extraer la siguiente instrucción a ejecutar y para leer o escribir un operando o resultado en memoria. Esto se soluciona fácilmente mediante dos sumadores distintos. una de las etapas tendrá que detener su ejecución y esperar a que quede libre el recurso necesario.

como los registros. de tal manera que dos etapas pueden coincidir en el recurso en el mismo ciclo. la etapa W podría escribir en un registro en el primer subciclo.24 .Para mejorar el acceso simultáneo a algunos recursos. Arquitectura de Computadores Segmentación del Cauce . y otra instrucción podría leer su contenido en el segundo subciclo. el ciclo se divide en dos subciclos. Por ejemplo. desde la etapa D (lectura de registros).

Las dependencias de datos se producen cuando dos instrucciones comparten un dato (operando o resultado). Veamos. pero una instrucción posterior. la única dependencia verdadera de datos es la que da lugar a riesgo de tipo RAW. los otros dos tipos son “dependencias de nombre” y dependen de las características del cauce. Ik. realiza una lectura de esa variable antes de que Ij haya terminado la operación escribiendo la variable compartida. WAR y WAW). Arquitectura de Computadores Segmentación del Cauce . pero ahora vamos a ocuparnos de la verdadera dependencia de datos (RAW). Hay tres tipos de dependencias de datos: •  Verdadera dependencia de datos à RAW (Read After Write) •  Antidependencia à WAR (Write After Read) •  Dependencia de salida à WAW (Write After Write) Los distintos tipos de dependencias pueden dan lugar a otros tantos tipos de “riesgos de datos” (RAW.25 . La situación es la siguiente: Una instrucción Ij actualiza el valor de una variable. que viene dada por la propia lógica del programa. Realmente. Más adelante trataremos las dependencias de nombre. en las siguientes páginas ejemplos concretos de esta dependencia de datos y varias soluciones propuestas.

26 . es decir. por lo que el resultado del programa será incorrecto. Obviamente. la dependencia que se denomina “lectura después de escritura” (Read After Write. el otro es mediante la detección y resolución. Hay dos opciones básicas para resolver este problema de dependencia de datos. o RAW) puede producirse entre las instrucciones I2 e I3 si la instrucción dmul lee el contenido de R1 (en el segundo subciclo de t4) antes de que el resultado de la suma anterior (en el primer subciclo de t6) se cargue en él. Arquitectura de Computadores Segmentación del Cauce . la operación dmul no se ejecutará con los operandos esperados por el programador.En el programa del ejemplo. pero sí de detectarlo en caso de que se produzca y solucionarlo de alguna manera. uno es mediante la prevención: evitando que pueda llegarse a esta situación de dependencia. Veámoslas en detalle. no preocupándose de evitarlo.

intercambiando el orden I2 por I1 e I3 por I4. Como se puede apreciar. Este retraso puede conseguirse insertando un número K de instrucciones entre I1 e I2. en este programa el compilador puede detectar la dependencia de datos y reorganizar las instrucciones para retardar el acceso al registro R1 hasta que esté actualizado. El problema de la dependencia de datos entre una instrucción I1 y otra instrucción I2 que le sigue puede prevenirse retrasando la ejecución de I2 un número K de etapas hasta que desaparezca el problema de que I2 lea un operando que I1 no ha escrito todavía. para evitar la dependencia de I3 respecto a I2. se escribe el resultado de daddi en R1. se requiere que I3 comience su ejecución tres ciclos después de que lo haga I2. Como vemos. Por lo que hemos visto en el ejemplo de la página anterior. se lee el operando R1 de dmul). Ejemplo 1: En la figura tenemos el ejemplo de un programa en el que hay una dependencia entre las instrucciones I2 e I3 a causa del registro R1.La dependencia de datos: Prevención. Arquitectura de Computadores Segmentación del Cauce . (Suponemos que en el primer subciclo de t6. Debe quedar claro que esta reorganización solamente puede hacerse si se mantiene la semántica original del programa. Esto significa que el compilador tiene que reordenar el programa para encontrar K instrucciones que puedan ejecutarse después de I1 y antes de I2 sin que por ello varíe la estructura lógica del programa. esto se ha conseguido con la reorganización que ha realizado el compilador.27 . y en el segundo subciclo.

pero a expensas de un compilador más complejo y una pérdida de tiempo si es necesario insertar instrucciones NOP (cuando no se puede reordenar el programa para insertar instrucciones útiles). sin modificar la lógica del programa. En este caso vemos que las instrucciones de este fragmento no se pueden reordenar sin alterar la lógica del programa. Ejemplo 2: En el ejemplo inferior tenemos el fragmento de un programa en el que también hay dependencias entre las instrucciones I1. por lo que el compilador inserta las instrucciones NOP necesarias para evitar la ejecución errónea de instrucciones por las dependencias de datos. I2 e I3. La ventaja de la solución basada en la prevención es que no se requiere hardware adicional.Si el compilador no puede reorganizar el código para encontrar estas K instrucciones que decíamos arriba. debe insertar operaciones NOP (No Operación) entre las operaciones dependientes.28 . Arquitectura de Computadores Segmentación del Cauce .

La dependencia de datos: Detección y resolución. Resolver las dependencias significa hacer algo para retrasar la ejecución de I2 o para acelerar. La aproximación más sencilla para evitar los problemas de dependencias de datos con ayuda del hardware es detener la actividad en las etapas necesarias del pipeline hasta que desaparezca la dependencia. • Detener el pipeline. en la medida de lo posible. es decir. Arquitectura de Computadores Segmentación del Cauce . la entrega a I2 del resultado que produce I1. primero se detecta la dependencia y después se detiene el pipeline a partir de la instrucción dependiente hasta que desaparece la dependencia. Con esta estrategia. esto significa detener las instrucciones que siguen a la instrucción daddi desde el ciclo 4 hasta que el registro R1 pueda leerse debidamente actualizado en segundo subciclo de t6. Veamos dos posibilidades de resolución (no excluyentes) para cuando se detecta una dependencia de datos entre dos etapas del pipeline. En el ejemplo de la figura. Este método requiere un hardware adicional en la CPU. Detectarlas significa que debe darse cuenta de que en un momento dado hay dos instrucciones arrancadas I1 e I2. hasta que se pueda ejecutar correctamente la instrucción dependiente. El dispositivo hardware que detecta estas dependencias se denomina interlock.29 . tal que I2 depende de un resultado establecido por I1. pues se deben detectar las dependencias de datos durante la ejecución y resolver estas dependencias. Obsérvese que la detención de n ciclos del cauce tiene el mismo efecto que la inserción de n instrucciones NOP.

también se puede dirigir el resultado de la etapa E de I2 directamente a la entrada de la etapa E de I3. donde la I2 tiene una dependencia de datos de I1 (por R1). Este retraso puede evitarse redirigiendo (forwarding) el resultado de la etapa E de la instrucción I1 directamente a la entrada de la etapa E de la instrucción I2. se puede dirigir el resultado de la etapa E de I1 directamente a la entrada de la etapa E de I2. Veámoslo en detalle: Anticipación (data forwarding). obteniendo el mismo efecto que se obtendría en la ejecución de la etapa D de I2. la entrega a una instrucción I2 del resultado que produce una instrucción previa I1. Arquitectura de Computadores Segmentación del Cauce . e I3 la tiene a su vez de I2 (por R2). y entonces pueda continuar I2 en su etapa D y leer el resultado que produjo I1. En la figura se muestra el esquema de la ejecución de 3 instrucciones. En una dependencia de datos RAW.El otro modo de resolver las dependencias de datos mediante Detección y Resolución es acelerando. En este caso se consigue evitar totalmente la detención del pipeline. puede suceder que una instrucción I2 necesite un operando en la etapa D (decodificación y obtención de operandos) que debe producirlo en el mismo ciclo la instrucción I1 en su etapa E (ejecución). Igualmente. en la medida de lo posible. Para evitar la lectura incorrecta de datos o las paradas del cauce. pero hay otras situaciones en las que esto no es posible.30 . Esto obligaría a detener la instrucción I2 hasta que I1 escriba el resultado en su etapa W.

Como vemos. pero si no hubiera adelantamiento. la instrucción de suma pueda obtener el valor actualizado de R1 a la entrada de su etapa de ejecución . Arquitectura de Computadores Segmentación del Cauce .31 . pues habría que esperar a que se completara la etapa W de la instrucción de carga para dar paso a la etapa D (obtención de operandos) de la suma. se necesitaría una parada de 2 ciclos adicionales ciclos en la etapa F de la suma. en el ciclo siguiente. no se consigue hasta el final de la etapa M (la de acceso a memoria). pero en la situación de la instrucción de carga I1.Aquí tenemos otro caso de dependencias múltiples que se intentan resolver con anticipación. por lo que hay que detener I2 en su etapa D para dar tiempo a que I1 ejecute su etapa M y. en las instrucciones de carga no se consigue evitar por completo la parada del cauce (se requiere una parada de un ciclo). su resultado (R1).

Aquí mostramos algunas situaciones de adelantamientos en MIPS. Arquitectura de Computadores Segmentación del Cauce . lo cierto es que no se consigue ninguna ventaja con un adelantamiento. hay más de una secuencia de instrucciones que conduce a distintas situaciones de adelantamientos. 2 y 3) o desde el final de una lectura en memoria (casos 4. En el caso 5. pues en el mismo ciclo en el que la etapa M de la instrucción de carga puede adelantarle R1 a la instrucción de bifurcación en su etapa D.Como se ha mostrado en las páginas anteriores. 5 y 6) para cargar un registro. los adelantamientos siempre se producen desde el final de la etapa de ejecución E (casos 1. y la instrucción de bifurcación puede leerlo en el segundo subciclo de su etapa D. En los casos 3 y 5. el adelantamiento se produce hacia la etapa D. en cuyo caso.32 . El adelantamiento se produce hacia la etapa de la instrucción en la que se requiere el dato de entrada. escribiendo R1 en el primer subciclo. se ejecuta la etapa W de la instrucción de carga. ya que es la encargada de comprobar la condición de salto.

Cuando se alimenta una instrucción en la CPU. por lo que las instrucciones que se van alimentando y ejecutando están en direcciones consecutivas de memoria. hay que esperar a una etapa posterior para que se pueda saber si se cumple o no la condición de salto. una por ciclo). El flujo normal de ejecución de un programa es secuencial. las instrucciones de bifurcación (que suelen representar alrededor del 20% de las instrucciones ejecutadas) pueden romper el flujo constante de instrucciones alimentadas. lo primero que se suele hacer en la etapa Fetch es incrementar el registro Contador de Programa (PC) para conocer la dirección de la siguiente instrucción a ejecutar y extraerla en el siguiente ciclo de reloj. por lo que la etapa de alimentación de instrucción no sabe de dónde seguir alimentando instrucciones. Pero si se trata de una instrucción de salto condicional. Por desgracia.33 . ¡Tenemos un problema con los saltos! Arquitectura de Computadores Segmentación del Cauce .Ya hemos comentado que uno de los principales problemas en el diseño de un pipeline consiste en asegurar el mantenimiento de un flujo constante de instrucciones alimentando sus diversas etapas para así poder mantener también constante el ritmo de ejecución de instrucciones (idealmente.

con lo que se puede proseguir la extracción de instrucciones de la dirección del salto. por lo que esta etapa de alimentación no puede extraer la siguiente instrucción a una bifurcación hasta que ésta llegue a la etapa en la que ya se conoce la dirección de la siguiente instrucción a ejecutar. con lo que no hay más remedio que esperar a que la bifurcación llegue a la etapa de comprobación de la condición de salto y establezca la dirección de la siguiente instrucción a ejecutar. a continuación de la alimentación de la instrucción de bifurcación. Por esto. Arquitectura de Computadores Segmentación del Cauce . las etapas F. Afortunadamente. Este hardware de ayuda también extrae la dirección de salto. tales como la “bifurcación retardada”.34 . D… se van quedando vacías al no saber qué instrucción alimentar. pues puede ocurrir que la condición del salto se establezca precisamente en la instrucción anterior. Esto quiere decir que se debe detener la alimentación de instrucciones al pipeline hasta que en la etapa que corresponda se averigüe la dirección de la siguiente instrucción a ejecutar. A estas etapas vacías que aparecen se las denomina huecos de retardo (delay slots).Una instrucción de bifurcación condicional hace que la dirección de la siguiente instrucción a ejecutar no se conozca en la etapa F. Sin embargo. en el caso de las bifurcaciones condicionales no se puede hacer esto. las bifurcaciones incondicionales pueden detectarse en la fase de alimentación o extracción (fetch) si se le añade un poco hardware a esta primera etapa. Veamos estas dos primeras técnicas. En algunos sistemas. hay diversas técnicas que pueden evitar o minimizar el impacto de las instrucciones de bifurcación. la “predicción del salto” y algunas más.

en los procesadores que tienen bifurcaciones retardadas.35 . por lo que independientemente del resultado de la ejecución de la bifurcación. Ya hemos visto que cuando entra una instrucción de salto en el pipeline. siempre se ejecutan las h instrucciones siguientes. Arquitectura de Computadores Segmentación del Cauce . no se ejecutarán si la instrucción de bifurcación decide saltar. Para conseguir que se ejecuten siempre las h instrucciones que siguen a una bifurcación. Pero claro. se producen h huecos de retardo por lo que hay que esperar h ciclos hasta que llega la siguiente instrucción de la secuencia a ejecutar. las instrucciones de salto no tienen efecto hasta h instrucciones después de su ejecución. si estas instrucciones están en memoria inmediatamente después de la instrucción de bifurcación. De esta manera no se producen los huecos de retardo. independientemente de si se toma la bifurcación o no. Estaría bien que estos huecos se pudieran rellenar con instrucciones que siempre se deban ejecutar.El problema de los saltos: Bifurcación retardada. según lo que sabemos hasta ahora.

I10. I6. Es decir I7. I7. la secuencia es: I1. Esto es así porque el efecto de la bifurcación se retarda un ciclo de reloj. I5. en la que I6 es la instrucción de salto condicional a la instrucción I11. haya o no bifurcación. I3. I4. I3. I12. . I8.36 . después de alimentar una instrucción de salto. I9. I11. I6.. se siguen extrayendo y ejecutando las instrucciones siguientes. es decir.. según su orden en la memoria. I5. I4. I3. I4.. . I5. En una CPU sin saltos retardados. I2. Arquitectura de Computadores Segmentación del Cauce . I11. I2. I2. I7. I11. I12.. la secuencia de instrucciones ejecutadas cuando la bifurcación no tiene lugar es: I1. se establece en el contador de programa la dirección indicada en la instrucción de salto.. será ya la correspondiente a la de la dirección indicada en dicha instrucción de salto. Después.Supongamos la serie de instrucciones que se muestra aquí arriba. Si a este mismo procesador (con un hueco de retardo en las bifurcaciones) se le ponen bifurcaciones retardadas.. I6. se ejecuta siempre. con lo que la 2ª instrucción después de la de salto. durante un ciclo más de reloj. . Mientras que cuando sí se produce la bifurcación. la secuencia de instrucciones ejecutadas cuando se produce la bifurcación es: I1. I12.

37 . en un ensamblador hipotético. como cuando sí se toma.Aquí tenemos un ejemplo. Arquitectura de Computadores Segmentación del Cauce . en el que para un programa dado (el de la izquierda). se muestran en la parte derecha las dos posibilidades de ejecución en un procesador con un hueco de retardo en los saltos: tanto cuando no se toma la bifurcación.

I4. . sabiendo lo que sucede en los procesadores con bifurcaciones retardadas (tarda un ciclo más en bifurcar realmente).. la secuencia de instrucciones que se ejecuta es: I1 – I2 – I3 – I5 – I6 – I4 – I7 – I8 – I9 – I10 – I11 – I12 –. Así. I12. suponiendo que no se altera la semántica del programa. Cuando no se produce la bifurcación. es decir. I2. I3. Si la bifurcación tiene lugar. vamos a intentar reordenar nuestro fragmento de código para que su ejecución se produzca con la misma semántica que la esperada en un procesador sin saltos retardados.. una instrucción que queremos que se ejecute siempre (se produzca el salto o no). I7. quedando entonces la secuencia de instrucciones en memoria así: I1.. I10. al alimentar una instrucción de salto condicional habría que detener la alimentación de instrucciones hasta que la instrucción de salto pasase por la etapa de decodificación (hasta saber cuál es la siguiente instrucción a ejecutar). I5.. después de la instrucción de salto vamos a poner una de las instrucciones que hay antes de la de salto. Ahora vamos a ejecutar este programa en nuestro procesador con bifurcaciones retardadas de un ciclo.A partir de un fragmento de código escrito para un procesador sin saltos retardados. si se va a ejecutar en una CPU con saltos con un hueco de retardo.. I6.38 . Arquitectura de Computadores Segmentación del Cauce . Con bifurcación retardada se aprovechan ese ciclo perdido en alimentar y ejecutar una instrucción que se desea ejecutar incondicionalmente antes de que la instrucción de bifurcación tenga lugar (se salte o no). las instrucciones se ejecutarán en este orden: I1 – I2 – I3 – I5 – I6 – I4 –I11 – I12 –. Si no hubiese bifurcación retardada. I9. I8. Así.. I11. podríamos mover la instrucción I4 y ponerla justo a continuación de I6 (la bifurcación condicional).

que debe saber cómo reorganizar el código para rellenar los huecos de retardo con instrucciones útiles (de la misma manera que se hacía con las dependencias de datos).39 .Esta técnica de los saltos retardados requiere la colaboración del compilador. Si el compilador no encuentra una manera de reordenar el código sin afectar a su semántica. debe insertar tantas operaciones NOP con huecos de retardo como sean necesarias para las bifurcaciones de ese procesador. Arquitectura de Computadores Segmentación del Cauce .

sería ventajoso que cuando el procesador se encuentra una instrucción de salto suponga que el salto sí se va a efectuar realmente. Otra técnica para reducir el problema de las bifurcaciones consiste en intentar predecir si una instrucción de bifurcación saltará o no. una bifurcación al final de un bucle salta al comienzo de éste todas las veces excepto la última. Por ejemplo.El problema de los saltos: Predicción del salto. Según esto. y cuando la etapa de alimentación detecte una bifurcación. Arquitectura de Computadores Segmentación del Cauce .40 . Si por el contrario resulta que no se realiza el salto. empiece a extraer instrucciones de la dirección de destino del salto. pues las instrucciones de la dirección del salto son las que ya se están alimentando. resulta que efectivamente se salta. Si una vez que se ejecuta la instrucción de bifurcación. se debe vaciar el pipeline (desechar todas las instrucciones erróneamente alimentadas) y empezar a alimentar las instrucciones que siguen en secuencia. la ejecución continúa normalmente.

Es decir.41 . ¡Y si al ejecutar la bifurcación no se realiza el salto! ¡Nos encontramos que algunas instrucciones ya se han empezado a ejecutar en las etapas anteriores! Con ejecución especulativa se debe tener cuidado de que en las etapas anteriores a la de ejecución no se modifiquen registros o posiciones de memoria hasta que no se confirme que la predicción realizada ha sido la acertada. ahora lo normal será suponer que la bifurcación no se tomará hasta la última pasada del bucle. Esto que hemos visto se denomina ejecución especulativa. por lo que se empiezan a alimentar instrucciones y a pasarlas a las siguientes etapas del pipeline antes de que la instrucción de bifurcación finalice su etapa de ejecución. Supongamos que se predice que el salto tendrá lugar. hay veces que conviene suponer una cosa y otras veces otra. Arquitectura de Computadores Segmentación del Cauce . pues las instrucciones pueden empezar a ejecutarse antes de que el procesador sepa que las instrucciones alimentadas son las realmente correctas.Si ahora suponemos que el control del bucle se realiza mediante una instrucción al comienzo del mismo.

la mejora es despreciable. Para ello. Ciertos estudios estadísticos dicen que conservando solamente el resultado de la última ejecución (con un bit) ya se obtiene una gran probabilidad de acierto (del orden del 90%) y con la historia de las cuatro últimas ejecuciones (dos bits) se mejora ligeramente. Por esto. Arquitectura de Computadores Segmentación del Cauce . en ejecución. en la CPU se debe llevar la cuenta de los resultados de las últimas ejecuciones de cada bifurcación. siempre que se alimente esa instrucción de bifurcación se hará la misma predicción. para lo cual el hardware del procesador debe establecer la posibilidad de que haya o no salto cada vez que se encuentre una cierta instrucción de bifurcación. manteniendo una historia mayor. lo que quiere decir que.42 . La predicción se puede mejorar si se realiza dinámicamente. se la conoce como predicción estática.La repetición de la bifurcación que se toma en el bucle la puede detectar el compilador y establecer la predicción mediante un cierto código de operación en la bifurcación.

Como la predicción es “no saltar”. se continúa con la Decodificación. pero hasta el final de esta etapa no se sabrá si habrá que saltar o no. y hay que esperar al final de la Decodificación para poder alimentar la instrucción de destino del salto. Para la arquitectura MIPS. en este ciclo no se puede extraer ninguna instrucción. si la condición se evaluara como falsa (no saltar). en la etapa F se alimenta la siguiente instrucción en memoria. con una porción de código concreta y con los mismos datos. Por el contrario. Como la predicción es “saltar”. cuando es “saltar”. después de alimentar la instrucción de salto. para decidir por dónde continúa extrayendo instrucciones. se pierde un ciclo tanto con una predicción de “saltar” como de “no saltar”.43 . con la predicción de NO SALTAR. se continúa con la Decodificación. Como vemos. Predicción SALTAR: Igual que antes. en este ciclo se querría extraer la siguiente instrucción de la dirección del salto. por lo que habrá que eliminar la instrucción daddi del cauce y empezar a extraer y ejecutar la instrucción de destino del salto. Al final de la etapa D se ve que se ha cometido un fallo en la predicción. vamos a ver lo que sucede cuando la predicción es “no saltar” y. posteriormente. sí se podría seguir alimentando instrucciones de la siguiente dirección de memoria.Como hemos visto. ante una condición que establezca que se debe saltar. por lo que su predicción es NO SALTAR. en MIPS 64 no tiene ninguna utilidad predecir “Tomar el salto”. la predicción ante un salto puede ser “saltar” o “no saltar”. Se ha perdido un ciclo de tiempo. Arquitectura de Computadores Segmentación del Cauce . Predicción NO SALTAR: Después de alimentar la instrucción de salto. Por lo que hemos visto. pero como hasta el final de la Decodificación tampoco se conoce la dirección del salto. en MIPS.

Las instrucciones de sumas y restas en aritmética entera pueden pasar por la etapa de ejecución realizando su cometido en un solo ciclo. En este capítulo vamos a ver posibles soluciones a esta cuestión y también los problemas que van a surgir.44 . pero hay otras operaciones. Arquitectura de Computadores Segmentación del Cauce . como la multiplicación. las instrucciones con datos de coma flotante. que no pueden ejecutar la operación de la etapa E en un solo ciclo. la división o. en general.

45 . haciéndolas tan lentas como las de coma flotante. pero esto no sería práctico. Este último problema se puede solucionar si dotamos al cauce de múltiples unidades funcionales en la etapa E: una para enteros. para aritmética en coma flotante. otras para multiplicación. Esto también tendría la pega de que la ejecución de una instrucción de coma flotante pararía el cauce hasta su terminación. etc. una opción sería alargar el tiempo del ciclo de reloj hasta el necesario para ejecutar las instrucciones de coma flotante. Para adaptar esto a nuestro pipeline. porque estaríamos ralentizando la ejecución del resto de las instrucciones. Veámoslo en la siguiente página Arquitectura de Computadores Segmentación del Cauce . hasta más de un centenar. pueden durar desde un par de ciclos. Las operaciones en coma flotante requieren bastante más tiempo en ejecutarse que las de la aritmética entera. pero los procesadores deben soportar también operaciones en coma flotante. como la raíz cuadrada. como la negación. división. Otra posibilidad podría consistir en mantener la duración del tiempo de ciclo de los enteros y repetir la etapa de Ejecución tantas veces como fuera necesario como para ejecutar cada instrucción de coma flotante.La arquitectura de MIPS64 que hemos visto hasta ahora solamente contempla la aritmética con enteros.

disponiendo de varias unidades funcionales. y gestión de bifurcaciones.46 . Ahora. cargas y almacenamientos. también de multiplicación en coma flotante. •  División de enteros y coma flotante (requiere 24 ciclos). que quedará detenida durante 7 ciclos hasta comenzar su ejecución . esta última tendrá que esperar a que termine completamente la primera para comenzar su ejecución. es decir. •  Sumas y restas y conversiones en coma flotante (requiere 4 ciclos). si comienza a ejecutarse una operación de coma flotante. Pero seguimos teniendo un problema. no impediría que inmediatamente a continuación pase a ejecutarse una instrucción de suma de enteros. •  Multiplicador de enteros y coma flotante (se ejecuta en 7 ciclos). Arquitectura de Computadores Segmentación del Cauce . Si a una operación en multiplicación en coma flotante (que es de larga duración) le sigue otra más.Nuestro nuevo cauce podría tener las siguientes unidades funcionales: •  Una unidad principal de enteros. ¡Esta es la situación que teníamos antes de inventar el pipeline! Veamos en la página siguiente cómo se resuelve este problema.

En nuestro MIPS. solamente requieren un ciclo. las sumas en coma flotantes se ejecutaran en 4 ciclos. Arquitectura de Computadores Segmentación del Cauce .47 . Ya que esta última unidad funcional no está segmentada. y requiere 24 ciclos de reloj para ejecutarse. se pueden producir riesgos estructurales si hay dos divisiones consecutivas o cercanas en el tiempo. cada una de un ciclo de duración. ya se podría arrancar la siguiente instrucción. la unidad funcional de las divisiones no está segmentada. aunque también fuera de multiplicación en coma flotante. en 7. y las multiplicaciones. un ciclo después del comienzo de la ejecución de una instrucción de multiplicación en la unidad de coma flotante.La solución a este problema es obvia: hay que segmentar las unidades de coma flotante en múltiples etapas. E. las instrucciones que se ejecuten en la unidad de enteros. Como vemos en el gráfico de nuestro ejemplo. Así.

Arquitectura de Computadores Segmentación del Cauce .Ya que las unidades funcionales multiciclo duran más. hay mayores riesgos. pues su unidad funcional no está segmentada. debe esperar en D a que finalice la etapa E de la división anterior. Dadas dos instrucciones de división consecutivas. por lo que antes de emitir la segunda división (pasarla a su etapa de ejecución). la segunda no puede arrancarse un ciclo después de la primera. Comencemos viendo los riesgos estructurales. estructurales y de datos.48 . El caso de la división es muy claro.

En cambio. sí compiten realmente por utilizar W. Este es el caso del ejemplo de arriba. en el que tres instrucciones compiten por la etapas M y W. por lo que el acceso a memoria no supone un riesgo estructural. la etapa de escritura de registros. Obsérvese que aunque las 3 instrucciones llegan al mismo tiempo a la etapa M. pues todas ellas generan un resultado cuyo destino es un registro. Arquitectura de Computadores Segmentación del Cauce . Veamos cómo se soluciona este conflicto en la página siguiente. en un momento dado puede haber varias instrucciones en el cauce que lleguen a un punto en el que intenten ejecutar la misma etapa al mismo tiempo. solamente la instrucción de carga la utiliza realmente (las otras dos utilizan registros).Ya que algunas instrucciones duran más ciclos que otras.49 .

Ante el problema estructural de la competencia por un recurso. es la que tiene más probabilidades de causar más riesgos de datos a otras instrucciones. pueden quedar detenidas en la etapa M. El resto de las instrucciones que compiten por entrar en la etapa W. se podría disponer de un conjunto de registros generales con más de un puerto de escritura. estas instrucciones quedan detenidas en la etapa D. Normalmente. Arquitectura de Computadores Segmentación del Cauce . pues mientras no avance. de una en una. la solución adoptada consiste en detectar la situación del riesgo estructural (competencia por el recurso). a la espera de que W quede libre. pues estas situaciones solamente se producen en muy raras ocasiones. detener las instrucciones que compiten y dejarlas continuar en secuencia. que es donde se comprueban los riesgos estructurales. En el caso de MIPS. pero esto no suele hacerse. Lo razonable es dejar continuar la instrucción de mayor latencia (la que genera mayor retardo).50 .

Las dependencias de datos son las que existen entre dos instrucciones que comparten datos. •  Verdadera dependencia de datos à RAW (Read After Write) •  Dependencia de salida à WAW (Write After Write) •  Antidependencia à WAR (Write After Read) En los cauces con operaciones multiciclo. Las dependencias de nombre se producen cuando dos instrucciones utilizan el mismo registro o dirección de memoria (comparten el nombre).51 . pero realmente no hay flujo de datos entre tales instrucciones (no comparten el dato). La verdadera dependencia de datos (RAW) viene dada por la propia lógica del programa. además de que las dependencias RAW se pueden producir más fácilmente. Arquitectura de Computadores Segmentación del Cauce .Ya habíamos visto los problemas que se pueden producir debidos a dependencias entre operaciones cercanas en el tiempo. Ahora. estos problemas se pueden complicar con las operaciones multiciclo y. Hay dos tipos de dependencias de nombre: antidependencias y dependencias de salida. mientras que las otras dos pueden producirse dependiendo de las características del cauce del procesador. Las dependencias entre instrucciones pueden ser de datos y de nombre. también aparecen los otros dos tipos de dependencias. Los distintos tipos de dependencias pueden dan lugar a otros tantos tipos de “riesgos de datos” (RAW. además. WAR y WAW). veremos que aparecen nuevos tipos de riesgos de datos.

y el almacenamiento puede leer R1 en el segundo subciclo. aunque la escritura y la lectura de R1 coinciden en el mismo ciclo. la suma puede escribir el resultado en R1 en el primer subciclo. las cosas cambian. las dos operaciones de suma y almacenamiento de enteros pueden ejecutarse sin ningún problema pese a que tienen la dependencia de R1. En el ejemplo de arriba. Ante este escenario. con las operaciones multiciclo. hasta que el operando R1 quede actualizado en la etapa W de la suma.52 . ya que. Ahora nos encontramos que cuando la operación de almacenamiento llega a la etapa D para leer el operando R1. la solución de MIPS es parar la instrucción de almacenamiento en la etapa D. pero ahora.Los riesgos RAW de las dependencias entre instrucciones ya los teníamos en los cauces convencionales. la suma todavía no ha llegado a la etapa W de escritura del resultado en R1. así que dura 3 ciclos más que con los enteros. se van a producir con mayor facilidad. como ya sabemos. La etapa de ejecución de la suma ahora requiere más tiempo. En el caso de que estas operaciones fueran con datos en coma flotante. por lo que es multiciclo. Arquitectura de Computadores Segmentación del Cauce .

Esto va a generar unas nuevas formas de dependencias de datos que veremos en las siguientes páginas.En el pipeline que habíamos visto hasta hace poco. por lo que. también en coma flotante. una suma. cuando solamente operábamos con enteros. varias instrucciones se ejecutaban simultáneamente en el cauce. La suma en coma flotante también es unos ciclos más larga que la carga y el almacenamiento que le siguen. por lo que finaliza después de su sucesora. igualmente. nos encontramos con el escenario de la parte inferior de la figura. Arquitectura de Computadores Segmentación del Cauce . e iban finalizando en el mismo orden en el que comenzaban. también finaliza más tarde que éstas. en el que ¡las instrucciones no finalizan en el mismo orden en el que se emiten! La multiplicación en coma flotante es una operación multiciclo muy larga. Con la incorporación de la coma flotante y la necesidad de incluir unidades funcionales multiciclo. pero 2 ciclos más corta.53 .

el valor que al final queda escrito en el registro F1 es el que deja la multiplicación. ésta finaliza después de la suma. Se debe preservar el orden de ejecución entre las dos instrucciones para asegurar que el valor que se escribe finalmente es el que corresponde a la instrucción j. aún empezando ésta posteriormente. Obsérvese que la suma no puede entrar en la etapa D hasta que la resta pasa a la etapa de ejecución. Así. Así. Obsérvese que este efecto solamente se produce cuando el resultado de la multiplicación se escribe (en F1) sin que ninguna instrucción lo utilice posteriormente como operando de entrada.La dependencia de salida (Write After Write) se produce cuando una instrucción i y una instrucción j escriben su resultado en el mismo registro o dirección de memoria. por ejemplo. Arquitectura de Computadores Segmentación del Cauce .54 . vemos que debido a la gran latencia de la multiplicación. ya no se produciría el problema pues al impedir el riesgo RAW entre la multiplicación y la resta. En el fragmento de programa de arriba. si entre la multiplicación y la suma hubiese una resta. lo cual es incorrecto. se evita también el riesgo WAW entre la multiplicación y la suma. que tomase el resultado de la multiplicación como dato de entrada.

Arquitectura de Computadores Segmentación del Cauce .  Detener la emisión de la suma (la instrucción posterior). Esta es la solución de MIPS a los riesgos WAW. O lo que es más fácil.  Desechar el resultado de la multiplicación. 2. sustituir la instrucción de multiplicación por una NOP (no Operación).55 . puesto que no se va a utilizar por ninguna instrucción. que este tipo de problemas solo se pueden producir con programas en los que hay secuencias de instrucciones sin sentido. hay dos soluciones para los riesgos de datos de tipo WAW: 1. No olvidemos tampoco. De esta manera se asegura que la instrucción posterior no escribirá el registro de destino antes que la anterior instrucción. es decir. hasta que la multiplicación (la anterior) entre en la etapa de Memoria. instrucciones que producen resultados que no son utilizados por ninguna instrucción posterior.En general.

En el ejemplo de arriba (en un procesador hipotético). si debido a una ejecución fuera de orden. También podría producirse en pipelines en los que. Estos problemas se producen en las arquitecturas con planificación dinámica. no sería el correcto.Los riesgos debidos a las antidependencias (WAR) entre dos instrucciones i y j se producen cuando la instrucción j escribe un registro o posición de memoria que la instrucción i utiliza como operando de entrada. Arquitectura de Computadores Segmentación del Cauce . que conllevan ejecución fuera de orden. por algún motivo. lo cual no era lo pretendido en el programa original. pues tomaría el valor producido como resultado de la resta. la resta se ejecuta antes que la suma. se produzcan lecturas en etapas finales y escrituras al comienzo del cauce. el operando de entrada F8 de la suma.56 .

Aunque la suma finaliza antes que la multiplicación. Además. la instrucción de suma deja el resultado en F2. en la etapa D. es decir. Arquitectura de Computadores Segmentación del Cauce . que lo utiliza la instrucción anterior como operando de entrada. Obsérvese que aunque la finalización de las instrucciones sí puede producirse fuera de orden. mucho antes de la etapa W de la suma. los operandos se leen enseguida. y las escrituras en registros se producen al final. en W. ya que utiliza un cauce estático. En este ejemplo. la emisión o arranque sí se realiza en orden. porque la multiplicación toma le valor de F2 en su etapa D.Los riesgos WAR no se producen en nuestro procesador MIPS. no afecta a la ejecución correcta. que se respeta el orden de emisión o arranque de las instrucciones.57 .