Diseño del procesador

Para mejorar el rendimiento del procesador, las instrucciones se segmentan en varias **etapas** que realizarán las tareas asociadas a cada parte de una instrucción. Esto se conoce como diseño **multiciclo**.

## Segmentación

Cada instrucción de un procesador se puede dividir en:

* Instruction fetch (**IF**): trae la instrucción de memoria.
* Decodificación de instrucción (**ID**): averigua que hay que hacer y con qué datos.
* Ejecución (**EX**): realiza la operación aritmética, calcula la dirección de memoria a acceder o averigua si hay que saltar y a qué dirección saltar.
* Acceso a memoria (**Mem**): trae un dato de memoria (etapa exclusiva de loads).
* Write-back (**WB**): escritura en memoria, tanto stores como en registros.

Estas etapas se pueden subdividir aún más, pero a nosotros nos bastará con esto.

## Riesgos

### Riesgos estructurales

Se producen cuando distintas instrucciones en distintas etapas compiten por los mismos recursos. Por ejemplo:

* Al hacer fech hay que actualizar el contador de programa PC (sumar), pero al mismo tiempo otra instrucción está usando la ALU.
* Al hacer fech se lee una instrucción de memoria, pero al mismo tiempo otra instrucción está en la etapa de acceso a memoria.
* En decodificación se lee de registros, mientras, en write-back se escribe.

Todo esto se soluciona duplicando recursos: una caché de instrucciones y otra de datos, banco de registros que lee y escribe simultáneamente, un sumador específico para el PC,...

### Riesgos de datos

Al ejecutar simultáneamente distintas etapas de distintas instrucciones pueden ocurrir ciertos fallos:

* Riesgos Lectura Después de Escritura (**LDE**): Ocurren cuando se lee un operando de un registro que va a ser modificado por una instrucción anterior.
* Riesgos Escritura Después de Lectura (**EDL**): Ocurren cuando una instrucción accede a un registro que ha sido sobreescrito por una instrucción posterior.
* Riesgos Escritura Después de Escritura (**EDE**): Ocurren cuando una instrucción anterior sobreescribe la escritura de una instrucción posterior.

En nuestro diseño solo tendremos que evitar los riesgos LDE. Algunas soluciones son:

* **Reordenar código**, pero no siempre se puede.
* Escribir en la primera mitad del ciclo y leer en la segunda, así los datos estarán disponibles un ciclo antes.
* Usar el dato recién salido de la ALU o de la memoria sin tener que guardarlo antes en un registro. Esto es un **cortocircuito o forwarding**.
* **Detener la instrucción** que necesita el dato (y todas las que le siguen) hasta que esté disponible.

Estas dos últimas opciones requieren hardware específico para detectar que va a haber un fallo y para solucionarlo adecuadamente.

### Riesgos de control

Las instrucciones de salto tardan en comprobar si hay que saltar o no y en calcular a dónde hay que saltar. Para evitar esto se adelanta el cálculo de la nueva dirección y la comprobación de la condición a la etapa de decodificación.

Esto hace que solo haya que esperar un ciclo. En ese ciclo se va ejecutando la instrucción siguiente a la de salto y si hay que saltar se le impide escribir, si no se le deja terminar. Otra opción es ejecutar siempre la instrucción siguiente y dejar que el compilador lo aproveche, esto se conoce como **salto retardado**.

Si la condición de salto necesita un dato que aún no está disponible se espera a que se calcule o se traiga de memoria y se hace un cortocircuito para usarlo cuanto antes sin tener que guardarlo en registro.

## Operaciones multiciclo

Las operaciones en coma flotante tardan varios ciclos. Esto hace que distintas instrucciones tarden distintos ciclos en realizar la etapa de ejecución.

### Riesgos estructurales

Hay unidades funcionales (para operar con decimales) que no pueden ser usadas simultáneamente por dos instrucciones, así que cuando una instrucción vaya a usar una unidad funcional que ya esté en uso tendrá que detenerse junto con todas las anteriores.

También es posible que dos instrucciones que van a usar unidades funcionales distintas terminen a la vez, y que luego haya un conflicto para entrar en la etapa de memoria. Para evitar esto se puede parar en la etapa de decodificación (en previsión de lo que va a pasar), o en el último ciclo de la etapa de ejecución.

### Riesgos de datos

#### LDE

Cuando una operación multiciclo proporciona un dato a alguna instrucción posterior el dato se cortocircuita en cuanto se tiene disponible, pero aún así puede hacer falta detener las instrucciones.

#### EDE

Instrucciones que tardan mucho pueden escribir después de instrucciones posteriores que tardan menos. Si no hay una dependencia de datos, con lo cual sería un riesgo LDE, la instrucción larga es inútil y se puede ignorar.

#### EDL

Estos riesgos siguen sin poder darse: se lee en decodificación y se escribe en WB.

## Rendimiento

El tiempo que tarda un programa en ejecutarse depende del nº de instrucciones, del tiempo de ciclo y de los ciclos por instrucción (CPI). Las NOP (no operaciones) no cuentan como instrucciones.

Los CPI se suelen contar con los ciclos de llenado de pipe, pero suelen ser despreciables. Tener o dejar de tenerlos en cuenta no es un error, pero hay que aclarar en todo caso cómo se están haciendo las medidas.