Copyright: Made with Shalom Help Maker www.danish-shareware.dk/soft/shelpm/


Introducción

¿Qué es SIMDE?

SIMDE es un simulador de Arquitecturas ILP (Instruction Level Parallelism) que incluye sus dos vertientes más características:
 Planificación dinámica: Cogiendo como ejemplo una máquina Superescalar.
 Planificación estática: Tomando como ejemplo una máquina VLIW.

El objetivo del simulador es servir de herramienta para el apoyo docente en la enseñanza de estas arquitecturas. Para ello hace hincapié en los aspectos más destacables de las dos vertientes estudiadas, así como en sus diferencias.

¿Qué NO es SIMDE?

SIMDE no pretende ser un simulador realista de estas arquitecturas. En su diseño contiene un gran número de simplificaciones que intentan clarificar el funcionamiento de la máquina a costa de un mayor rigor técnico. Algunos de los componentes de las máquinas funcionan de manera imposible de implementar en la práctica (o de costes prohibitivos).

El diseño de la máquina VLIW es extremadamente simple para resaltar aún más sus diferencias con la máquina Superescalar. Este diseño no tiene ninguna utilidad más que como máquina teórica.

SIMDE no es un compilador VLIW. Todas las optimizaciones del código y su posterior planificación las realiza el usario.

Funcionalidades

SIMDE permite:

 Cargar un único programa secuencial cada vez que servirá como base para la ejecución Superescalar o para diseñar un código VLIW.

 Modificar los parámetros de las máquinas Superescalar y VLIW.

 Crear, cargar o modificar un código de instrucciones largas que usar en la simulación VLIW. Además se añaden herramientas para facilitar la creación de este código, como el coloreado de bloques básicos o el chequeo automático del código creado para detectar inconsistencias.

 Modificar el contenido de la memoria y registros.

 Realizar simulaciones continuas o paso a paso de la máquina Superescalar, permitiendo el uso de breakpoints para detener la ejecución en un punto del código determinado.

 Realizar simulaciones continuas o paso a paso de la máquina VLIW, permitiendo el uso de breakpoints para detener la ejecución en un punto del código determinado.


ILP

ILP

El Paralelismo a Nivel de Instrucción es la capacidad de un conjunto de instrucciones de poder ser ejecutadas en paralelo.

Existen numerosas técnicas que intentan explotar esta capacidad, desde la segmentación hasta la emisión de múltiples instrucciones por ciclo. Es precisamente con este último grupo de máquinas con las que trabaja este simulador.

Existen dos claras vertientes para manejar la emisión múltiple (Multiple Issue), que se ven en los dos puntos siguientes.

Planificación Dinámica de Instrucciones

El hardware se encarga de reordenar las instrucciones para aprovechar el paralelismo, con lo que se emplea una ejecución fuera de orden (out_of_order). Las máquinas Superescalares suelen emplear esta técnica.

Planificación Estática de Instrucciones

El compilador se encarga de reordenar las instrucciones para aprovechar el paralelismo, con lo que se consigue una gran simplificación del hardware. Emplea ejecución en orden (in_order). Esta es la técnica básica en las máquinas VLIW.


Menú Archivo

Abrir...

Permite abrir un fichero con código secuencial.

Salir

Termina la ejecución del programa.


Menú Ver

Contiene las opciones de visualización del programa.

Bloques Básicos

Habilita la opción de colorear los bloques básicos en el código.

Barras de Herramientas

Permite seleccionar qué barras de herramientas se ven y cuáles no. Hay dos barras de herramientas definidas:

 La barra Estándar, que contiene las opciones básicas
 La barra de Ejecución, que permite realizar las simulaciones

Código Secuencial

Muestra/oculta el código secuencial cargado de fichero.


Menú Configurar

Contiene las opciones de configuración de las máquinas.

Configurar Superescalar

Abre la ventana de Configuración de la Máquina Superescalar, con la que se pueden modificar sus parámetros más importantes.

Configurar VLIW

Abre la ventana de Configuración de la Máquina VLIW, con la que se pueden modificar sus parámetros más importantes.

Instrucciones VLIW

Contiene los menús para diseñar un código VLIW:

 Crear Nuevo Programa VLIW: Permite crear un nuevo código VLIW
 Cargar Programa VLIW...: Permite cargar un código VLIW desde un fichero

Opciones

Contiene varias opciones del programa:

 Resetear Máquina al Iniciar: Si se deja marcada, cada vez que se inicie una nueva simulación la memoria y registros de la máquina se ponen a 0. Si no conserva los valores de la última ejecución.
 Chequear Código VLIW: Le indica al programa que chequee el código VLIW en busca de inconsistencias al terminar su diseño.
 % Fallos Caché Datos: Permite establecer el porcentaje de fallos de caché de datos al realizar una instrucción de carga (LOAD). 0 significa que no habrá ningún fallo y 100 significa que todos los accesos producen fallo.


Menú Ejecutar

Contiene todas las herramientas para realizar las simulaciones.

Seleccionar Máquina

Permite escoger la máquina con la que quiere realizarse la simulación.

 Seleccionar Superescalar
 Seleccionar VLIW

Iniciar

Permite comenzar la ejecución continua de la simulación. Si se pulsa mientras está ejecutandose otra simulación, se ofrece la opción de comenzar desde el principio. La ejecución continua sólo se detiene al llegar al final del programa o si encuentra un Break Point.

Pausa

Permite pausar una ejecución iniciada en modo continuo. Después puede proseguirse con la ejecución en modo continuo o paso a paso.

Paso

Permite comenzar (continuar) una ejecución paso a paso. Cada vez que se hace clic en este botón la simulación avanza un ciclo.

Parar

Detiene una ejecución poniendo el reloj a 0.

Componentes

Permite visualizar y modificar los componentes comunes de la máquina: registros y memoria.


Menú Ventana

Contiene las opciones para el control de las ventanas de la aplicación.

Mosaico

Coloca todas las ventanas como un mosaico.

Cascada

Coloca todas las ventanas en cascada.

Restaurar todo

Vuelve a mostrar todas las ventanas que estén minimizadas.


Menú Ayuda

Contenido

Muestra el contenido general de la Ayuda.

Buscar Ayuda Sobre...

Muestra la ventana de búsqueda en el índice de la Ayuda.

Cómo Usar la Ayuda

Explica cómo emplear las ventanas de Ayuda.

Acerca...

Información general de la Aplicación.


Barra de Herramientas Estándar

Contiene las opciones más comunes del programa.

 Permite abrir un fichero con código secuencial.

 Habilita la opción de colorear los bloques básicos en el código.

 Muestra/oculta el código secuencial cargado de fichero.

 Abre la ventana de Configuración de la Máquina Superescalar, con la que se pueden modificar sus parámetros más importantes.

 Abre la ventana de Configuración de la Máquina VLIW, con la que se pueden modificar sus parámetros más importantes.

 Permite establecer el porcentaje de fallos de caché de datos al realizar una instrucción de carga (LOAD). 0 significa que no habrá ningún fallo y 100 significa que todos los accesos producen fallo.


Barra de Herramientas de Ejecución

Contiene las herramientas que permiten llevar a cabo las simulaciones.

 Permite comenzar la ejecución continua de la simulación. Si se pulsa mientras está ejecutandose otra simulación, se ofrece la opción de comenzar desde el principio. La ejecución continua sólo se detiene al llegar al final del programa o si encuentra un Break Point.

 Permite comenzar (continuar) una ejecución paso a paso. Cada vez que se hace clic en este botón la simulación avanza un ciclo.

 Permite pausar una ejecución iniciada en modo continuo. Después puede proseguirse con la ejecución en modo continuo o paso a paso.

 Detiene una ejecución poniendo el reloj a 0.

 Permite escoger un componente de la máquina para visualizar.

 Permite cambiar la máquina con la que se quiere realizar una simulación.


Ventana Instrucciones

La Ventana de Instrucciones permite visualizar el código secuencial cargado desde un fichero.

Las instrucciones se muestran en orden secuencial.

En la primera columna aparece el número de orden de la instrucción, que servirá como Identificador. También aparecen en esta columna las etiquetas entre corchetes ([etiqueta:]) a continuación del número de instrucción.

La segunda columna es el código de la operación (opcode).

Las siguientes columnas son los operandos.

Breakpoints

Haciendo doble clic sobre cualquier campo de la instrucción se establece un Breakpoint válido para la ejecución superescalar (los Breakpoints de la máquina VLIW se indican sobre las instrucciones largas). El breakpoint se indica con el color rojo en la columna del Identificador. Para quitar el Breakpoint basta con volver a hacer doble clic.

Ocultar el código

Si se hace doble clic en el título con el nombre del fichero, se ocultará está ventana. Para volver a verla hay que ir al menú Ver => Código Secuencial..

Bloques básicos

Para colorear los Bloques Básicos del código basta con ir al menú Ver => Bloques Básicos.


Configurar Parámetros Superescalar

 Vaya a Configurar => Parámetros Superescalar.

Los parámetros configurables son el Número de U.F. y la Latencia de cada una.
Además se puede definir la latencia cuando hay un Fallo de Caché.

El otro parámetro modificable es el valor de Emisión, que indica el número de instrucciones que se emiten (y graduan) por ciclo.


Configurar Parámetros VLIW

 Vaya a Configurar=>Parámetros VLIW.

Los parámetros configurables son el Número de U.F. (excepto las U.F. de salto, limitadas a 1) y la Latencia de cada una.
Además se puede definir la latencia cuando hay un Fallo de Caché.


Ventana Registros, Memoria

Para ver los Registros de Propósito General, los de Punto Flotante o la Memoria se pueden emplear dos métodos:

 Ir al menú Ejecutar => Maquina Superescalar/VLIW => Componentes y elegir el componente correspondiente.

 Desde la Barra de Herramientas de Ejecución usar el cuadro combinado de componentes.

 La ventana permite ver un subconjunto de los elementos del componente seleccionado por el usuario.

La primera columna representa el índice o la posición, y la segunda columna representa el valor de esa posición (por claridad, los números en punto flotante se presentan siempre redondeados a 3 decimales).

Se presentan una serie de botones en la parte baja de la ventana:

 Permite seleccionar un subconjunto de elementos para mostrar mediante una lista de números o intervalos separados por comas (ej. 2,10-15,20).

 Permite seleccionar un subconjunto de elementos para ocultar mediante una lista de números o intervalos separados por comas (ej. 2,10-15,20).

 Guarda los cambios realizados en el contenido del componente.

 Cancela los cambios realizados en el contenido del componente.

 Pone todos los elementos seleccionados a 0.


Ventana Simulación Superescalar

En esta ventana se observa la estructura básica de la máquina Superescalar.

Componentes mostrados

 Prefetch: Unidad de prebúsqueda de instrucciones.

 Decoder: Decodificador de las instrucciones

 ROB<->GPR: Posición del ROB donde se está procesando un registro de propósito general (-1 si el registro no está asociado a ninguna entrada del ROB). Se muestra sólo un subconjunto de los elementos. Se pueden añadir o quitar elementos mediante los botones [image] y [image], indicándolos como una lista de números (o intervalos) separada por comas (ej. 2,12-18,20).

 ROB<->FPR: Posición del ROB donde se está procesando un registro de punto flotante (-1 si el registro no está asociado a ninguna entrada del ROB). Se muestra sólo un subconjunto de los elementos. Se pueden añadir o quitar elementos mediante los botones [image] y [image], indicándolos como una lista de números (o intervalos) separada por comas (ej. 2,12-18,20).

 Predicción Salto: Tabla de predicción de salto. Si vale F es que el salto que coincide con esa dirección no se toma; si vale V el salto se toma. Además de esto se muestra el valor binario de la entrada de la tabla entre paréntesis.

 ROB: Reorder Buffer.

 E.R.: Estaciones de Reserva.

 U.F.: Unidades Funcionales. En la parte superior aparece el nombre de la UF. Hay tantas columnas como UF de ese tipo estén declaradas. Cada columna representa una UF. Las filas representan el pipeline de la UF.

Alto y ancho de los componentes

El alto y ancho de la mayoría de los componentes puede modificarse poniendo el ratón sobre alguno de sus bordes y arrastrando manteniendo presionado el botón izquierdo del ratón. Tanto las ER como las UF pueden ocultarse haciendo doble clic sobre el nombre de la UF o ER correspondiente. Al hacer doble clic otra vez se volverá a mostrar.

Colorear las instrucciones

Si se hace doble clic con el ratón encima de una entrada del ROB puede seleccionarse un color para asociar con dicha entrada. De esta manera, se coloreará esta entrada y las entradas correspondientes en la ER y la UF (si existen).


Ventana Simulación VLIW

En esta ventana se observa la estructura básica de la máquina VLIW.

Componentes mostrados

 NaT (GPR): Bits de NaT (Not a Thing). Si muestran una V es que el registro está siendo usado como destino de un LOAD. Se pueden añadir o quitar elementos mediante los botones [image] y [image], indicándolos como una lista de números (o intervalos) separada por comas (ej. 2,12-18,20).

 NaT (FPR): Bits de NaT (Not a Thing). Si muestran una V es que el registro está siendo usado como destino de un LOAD. Se pueden añadir o quitar elementos mediante los botones [image] y [image], indicándolos como una lista de números (o intervalos) separada por comas (ej. 2,12-18,20).

 Reg. Pred.: Registros de Predicado. Una V indica que las operaciones asociadas a este registro se ejecutarán. Con F no se ejecutarán. Se pueden añadir o quitar elementos mediante los botones [image] y [image], indicándolos como una lista de números (o intervalos) separada por comas (ej. 2,12-18,20).

 U.F.: Unidades Funcionales. En la parte superior aparece el nombre de la UF. Hay tantas columnas como UF de ese tipo estén declaradas. Cada columna representa una UF. Las filas representan el pipeline de la UF.

Alto y ancho de los componentes

El alto y ancho de la mayoría de los componentes puede modificarse poniendo el ratón sobre alguno de sus bordes y arrastrando manteniendo presionado el botón izquierdo del ratón. Las UF pueden ocultarse haciendo doble clic sobre el nombre de la UF. Al hacer doble clic otra vez se volverá a mostrar.


Fichero Código Secuencial

Los Ficheros de Código Secuencial que se emplean como entrada permiten definir de forma sencilla un código secuencial mediante cualquier editor de textos. Todos los ficheros de código deben llevar la extensión .pla

Características

El fichero debe cumplir las siguientes características:
 La primera línea del fichero (que no sea un comentario) contiene el número de instrucciones del fichero.
 Cada instrucción debe ponerse en una nueva línea.
 Se permiten como separadores de operandos tabuladores o espacios.
 Las etiquetas se ponen al principio de la línea y deben terminar con ":".
 Los comentarios se indican con  "//". De ahí al final de la línea todo es un comentario.

Instrucciones

Las instrucciones permitidas están inspiradas en el repertorio MIPS IV. Se emplea la siguiente nomenclatura:

 Rn Registro de Propósito General n.
Ej.  R1, R0...
 Fm Registro de Punto Flotante m.
Ej.  F1, F0...
 #n Valor inmediato n.
Ej.  #12, #0...
 n(Rm) Dirección de memoria.
Ej.  (R1), 3(R4)...
 LAB: Etiqueta destino de un salto.
Ej.  LOOP1:, END:...

Las instrucciones permitidas son:
 DADDUI	Rn Rm #i
 ADDI	Rn Rm Rp
 MULTI	Rn Rm Rp
 ADDF	Fn Fm Fp
 MULTF	Fn Fm Fp
 LI	Rn i(Rm)
 LF	Fn i(Rm)
 SI	Rn i(Rm)
 SF	Fn i(Rm)
 BNE	Rn Rm LAB
 BEQ	Rn Rm LAB


Ejemplo Código Secuencial

// SIMDE v0.1
// Autor: Iván Castilla Rodríguez
// Utilidad: Programa de testeo de SIMDE
// Comentarios: El programa presupone q en la posición 50 (R2) de memoria tienes un vector de
// 5 elementos y quieres sumar a cada elemento una cantidad fija (en la posición de memoria
// 40). El resultado se coloca a partir de la posición 70 (R3) de memoria.
11
DADDUI	R2 R0 #50
DADDUI	R3 R0 #70
DADDUI	R4 R0 #40
LF	F0 (R4)
DADDUI	R5 R2 #5
LOOP:
LF 	F1 (R2)
ADDF	F1 F1 F0
SF	F1 (R3)
DADDUI 	R2 R2 #1
DADDUI	R3 R3 #1
BNE	R2 R5 LOOP


Crear Código VLIW

 Vaya a Configurar=>Instrucciones VLIW=>Crear Nuevo Programa VLIW.

Se abrirá la ventana de diseño de código VLIW, donde puede construir un código VLIW a partir de la configuración actual de la máquina y el código secuencial actualmente cargado.


Cargar Código VLIW

 Vaya a Configurar=>Instrucciones VLIW=>Cargar Programa VLIW.

Se le abrirá un cuadro de diálogo en el que podrá seleccionar el fichero ".vliw"que contiene el programa diseñado.

Después de cargarlo puede modificarlo.


Modificar Código VLIW

La ventana de diseño de Código VLIW se compone de una Rejilla de Diseñoen la que cada fila es una instrucción y cada columna, una U.F. de la máquina. La primera columna es el identificador de la instrucción larga.

Botones

Se dispone de una serie de botones para facilitar la creación del código:
 Añadir: Permite añadir más instrucciones (filas) a la Rejilla de Diseño.
 Eliminar: Permite eliminar la instrucción seleccionada de la Rejilla de Diseño.
 Limpiar: Deja la ventana de diseño en blanco.
 Aceptar: Guarda los cambios realizados en el código. Al pulsar Aceptar se realizan una serie de comprobaciones sobre el código. Los mensajes de error se devuelven de la forma: "Error en la operación # de la instrucción larga #", con lo que resulta sencillo localizar el fallo.
 Cancelar: Cancela los cambios realizados.
 Guardar: Guarda el código en un fichero.

"Construcción" del código

La creación del código VLIW es muy sencilla. Basta con arrastrar las operaciones desde la ventana de código secuencial hasta la ventana de código VLIW. El programa sólo permite arrastrar las operaciones a una U.F. donde puedan ser ejecutadas.
Las operaciones de salto deben ser configuradas en el momento de arrastrarlas. Debe indicarse:
 Instrucción destino: La instrucción larga destino del salto.
 Registro Predicado Verdadero: El Registro de Predicado que cambiará su valor a VERDADERO si el salto es tomado.
 Registro Predicado Falso: El Registro de Predicado que cambiará su valor a VERDADERO si el salto NO es tomado.
 Registro Predicado: Registro de Predicado asociado a esta operación.

Parámetros de la operación

Los parámetros de una operación pueden ser modificados en cualquier momento haciendo doble clic sobre la operación en concreto. Si se trata de una operación de salto aparecerán los parámetros que se nombraron antes; en otro caso simplemente se solicita el Registro de Predicado asociado a la operación.

Eliminación de una operación

Una operación puede eliminarse seleccionándola y pulsando la tecla SUPR.

Breakpoints

Puede añadirse un Breakpoint haciendo doble clic sobre el identificador de la instrucción.

Colorear zona de influencia

También puede observarse la zona de influencia de una operación haciendo CTRL + clic con el botón izquierdo del ratón sobre la misma. De esta forma se colorean las instrucciones durante las cuales no pueden planificarse operaciones que tengan operandos dependientes de la operación marcada o, en el caso de los saltos, las instrucciones en las que pueden usarse los registros de predicado asociados a ese salto.


Consejos Creación Código VLIW

La creación del código VLIW a partir del código secuencial es una tarea compleja, más si nosotros tenemos que hacer el trabajo del compilador. Incluyo en esta sección una serie de consejos y recomendaciones que pueden ayudar a obtener un código que funcione lo más rápidamente posible.

Consejos generales

 A partir de un código secuencial sólo podemos jugar con la colocación de las operaciones en el código VLIW. Las optimizaciones del código (desenrollado de bucles, software-pipelining...) se realizan sobre el código secuencial, creando un nuevo fichero de entrada.

 Piensa que el hardware de la máquina VLIW no realiza ninguna optimización sobre el código que le das, sino que todas las optimizaciones las realiza el compilador (TÚ). Para obtener tiempos de ejecución similares a la máquina Superescalar deberás esmerarte en la colocación de las operaciones en las instrucciones largas y optimizar el código secuencial todo lo que puedas.

Consejos de creación de código

 La forma más sencilla de construir el código es comenzar a arrastrar las operaciones en orden desde el código secuencial.

 Es importante fijarse en las dependencias RAW antes de arrastrar una operación. Colorear la zona de influencia de una operación (haciendo doble clic) puede ayudarnos a saber dónde colocar la siguiente instrucción.

 Los bucles son la parte fundamental del código. Una operación de salto cuyo destino sea una operación secuencial se convierte en un salto a una instrucción larga al arrastrarlo al código VLIW.

 El destino más obvio de un salto es la primera instrucción que contenga una operación del bloque básico destino del salto, pero no siempre es la mejor opción.

 Recuerda que las instrucciones largas se ejecutan completamente, no la mitad o sólo algunas de las operaciones. Ten en cuenta esto a la hora de poner en una misma instrucción operaciones que son destino de un salto con otras que no lo son.

 Aprovecha la posibilidad de repetir operaciones en el código. Tal vez quieras que la primera iteración de un bucle se ejecute de una forma para después aplicar predicación el resto de iteraciones.

 El uso de registros de predicado es una herramienta bastante potente que te permite ejecutar en paralelo operaciones de las dos ramas de un salto.

 Recuerda que puedes predicar cualquier operación, incluso otra operación de salto.

 La opción de Chequear Código VLIW no asegura que el código obtenido sea 100 % fiable, pero sí ayudará a detectar algunos errores.

 Aprovecha la configuración de los bancos de registros, que leen en la primera mitad del ciclo y escriben en la segunda mitad. Podrás ahorrarte un ciclo en muchas ocasiones.

Posibles errores

 Ten cuidado al asignar un registro de predicado a una operación. Asegúrate que esté en la zona de influencia del salto que utiliza esos registros de predicado.

 Para poder predicar una operación no debe terminar su ejecución antes de evaluar el salto, porque en ese caso no podrá cancelarse a tiempo si resulta pertenecer a la rama no tomada del salto.

 El algoritmo empleado para chequear el código creado es básicamente heurístico. En ocasiones detectará dependencias RAW que realmente no lo son, o no detectará otras que sí lo son. Recuerda emplearlo sólo como una referencia pero la validación final debes realizarla tú.


Estructura Común

Tanto la máquina Superescalar como la VLIW diseñadas para este simulador mantienen una estructura básica común.

Características Comunes

 Ambas máquinas están diseñadas para trabajar con palabras de 32 bits, tanto para los tipos de datos entero y flotante.

 El juego de instrucciones, basado en MIPS IV.

 Las dos máquinas son monoprograma. El código (tanto el secuencial en la máquina superescalar como el de instrucciones largas en la VLIW) siempre se coloca empezando en la dirección 0, por lo que los saltos son siempre a direcciones absolutas.

Elementos Comunes

 Memoria.

 Registros de Propósito General (GPR).

 Registros de Punto Flotante (FPR).


Juego de Instrucciones

El Juego de Instrucciones (Operaciones en la máquina VLIW) es común a las dos máquinas. Sin embargo hay ligeras diferencias en el comportamiento de algunas de las instrucciones.

DADDUI

Suma Entera con Inmediato sin signo
DADDUI Rd, Ro1, #Inm
Rd = Ro1 + Inm
Se opera en la UF de Suma Entera

ADDI

Suma Entera
ADDI Rd, Ro1, Ro2
Rd = Ro1 + Ro2
Se opera en la UF de Suma Entera

MULTI

Multiplicación Entera
MULTI Rd, Ro1, Ro2
Rd = Ro1 * Ro2
Se opera en la UF de Multiplicación Entera

ADDF

Suma Punto Flotante
ADDF Fd, Fo1, Fo2
Fd = Fo1 + Fo2
Se opera en la UF de Suma en Punto Flotante

MULTF

Multiplicación Punto Flotante
MULTF Fd, Fo1, Fo2
Fd = Fo1 * Fo2
Se opera en la UF de Multiplicación en Punto Flotante

LI

Load Entero
LI Rd, Inm(Ro)
Rd = MEM[Ro + Inm]
Se opera en la UF de Memoria

LF

Load Flotante
LI Fd, Inm(Ro)
Fd = MEM[Ro + Inm]
Se opera en la UF de Memoria

SI

Store Entero
SI Ro, Inm(Rd)
MEM[Rd + Inm] = Ro
Se opera en la UF de Memoria

SF

Store Flotante
SF Fo, Inm(Rd)
MEM[Rd + Inm] = Fo
Se opera en la UF de Memoria

BNE

Salta si distinto
BNE Ro1, Ro2, Etiqueta
Si (Ro1 != Ro2)
Saltar a instrucción apuntada por Etiqueta
Se opera en la UF de Salto

BEQ

Salta si igual
BEQ Ro1, Ro2, Etiqueta
Si (Ro1 == Ro2)
Saltar a instrucción apuntada por Etiqueta
Se opera en la UF de Salto


Memoria

La memoria emplea un esquema ficticio con cachés separadas para datos e instrucciones.

Memoria Principal

La memoria principal contiene 1024 palabras de 32 bits.

Caché de Instrucciones

La caché de instrucciones está diseñada para contener completamente el programa secuencial (y el programa VLIW si se está empleando), de tal manera que nunca se producen fallos de caché al intentar leer una instrucción.

Caché da Datos

La caché de datos genera fallos de lectura de manera aleatoria. El porcentaje de fallos es un parámetro definido por el usuario.


Modos de Direccionamiento

El repertorio de instrucciones de la máquina sólo permite direccionamiento de memoria indexado de la forma Inm(Rn).

La dirección se calcula sumando al valor del registro indicado (Rn) el valor inmediato (Inm). Los accesos a memoria se hacen siempre a palabras completas, de tal manera que el valor inmediato se interpreta directamente como un valor de palabra (y no como byte, como suele ser más habitual).


Ejemplo Direccionamiento

// En este ejemplo se accede a la palabra de memoria 5 (3 + 2) para guardar el contenido de R1
DADDUI	 R4 R0 #2
SI	 R1 3(R4)


Registros de Propósito General

Banco de 64 registros de 32 bits.

Se denotan R0, R1, R2, ..., R63.

R0

El valor de R0 se mantiene siempre a 0.

Acceso

En la máquina VLIW la lectura se realiza en la primera mitad del ciclo y la escritura en la segunda mitad. De esta manera se evitan los riesgos WAR. En la máquina Superescalar no tiene sentido este añadido, ya que este tipo de dependencias se eliminan con el ROB.


Registros de Punto Flotante

Banco de 64 registros de 32 bits. Emplea simple precisión.

Se denotan F0, F1, F2, ..., F63.

Acceso

En la máquina VLIW la lectura se realiza en la primera mitad del ciclo y la escritura en la segunda mitad. De esta manera se evitan los riesgos WAR. En la máquina Superescalar no tiene sentido este añadido, ya que este tipo de dependencias se eliminan con el ROB.


Unidades Funcionales

Las Unidades Funcionales (UF) son las únidades básicas de ejecución de la máquina.

Son segmentadas, y cada etapa del pipeline dura 1 ciclo exactamente. De esta manera, cada ciclo puede entrar una nueva instrucción a menos que tenga una dependencia verdadera con la instrucción anterior. En ese caso, deberá esperar hasta que la instrucción anterior haya acabado completamente su ejecución. A este tiempo lo denominamos latencia de la UF, y coincide con el número de etapas del pipeline.

Tipos

 Suma entera: Para efectuar las operaciones ADDI y DADDUI, y el cálculo de direcciones en la VLIW (en la máquina superescalar esta función se considera integrada en la UF de memoria).

 Multiplicación entera: Efectúa la operación MULTI.

 Suma flotante: Efectúa la operación ADDF.

 Multiplicación flotante: Efectúa la operación MULTF.

 Memoria: Se encarga de todas las operaciones referentes a memoria (LI, SI, LF, SF). En la máquina Superescalar se considera que tiene integrada una ALU para el cálculo de direcciones, mientras que en la VLIW sólo representa el tiempo de acceso a la memoria

 Salto: Se encarga de las operaciones de salto, evaluando las condiciones y cambiando el PC (y la tabla de predicción en la máquina Superescalar).


Máquina Superescalar

Características

 Control de la máquina basado en el algoritmo de Tomasulo

 El parámetro más importante de esta máquina es el Grado de Emisión (nos referiremos a este parámetro simplemente como Emisión a partir de ahora), que es el número máximo de instrucciones que pueden emitirse por ciclo, pero también el número máximo de instrucciones que pueden graduarse (commit) por ciclo.

 Emplea predicción dinámica de saltos.

Componentes

 Prefetch: Unidad de prebúsqueda de instrucciones.

 Decoder: Decodificador de las instrucciones

 ROB<->GPR: Posición del ROB donde se está procesando un registro de propósito general

 ROB<->FPR: Posición del ROB donde se está procesando un registro de punto flotante

 Predicción Salto: Tabla de predicción de salto

 ROB: Reorder Buffer

 E.R.: Estaciones de Reserva

 U.F.: Unidades Funcionales

 ALU de cálculo de direcciones: Unidad para calcular las direcciones de las instrucciones de memoria


Unidad de Prebúsqueda

La Unidad de Prebúsqueda (Prefetch Unit) se encarga de adquirir de forma transparente al resto de la máquina las instrucciones del flujo de ejecución.
Para ello tiene en cuenta la tabla de predicción de salto.

Esta unidad mantiene en cada ciclo hasta 2 x Emisión instrucciones.


Decodificador

El Decodificador (Decoder) se encarga de interpretar las instrucciones para enviarlas a su E.R. correspondiente.
Implementa la lógica de control que permite retener el flujo si el ROB o la E.R. a la que va la próxima instrucción están llenos.


ROB<->GPR

Es el campo Qi del que se habla en el algoritmo de Tomasulo. Indica si un registro de propósito general está siendo usado por alguna entrada del ROB (en cuyo caso se mostrará el número de la entrada) o no (-1).


ROB<->FPR

Es el campo Qi del que se habla en el algoritmo de Tomasulo. Indica si un registro de punto flotante está siendo usado por alguna entrada del ROB (en cuyo caso se mostrará el número de la entrada) o no (-1).


Predicción Salto

La Tabla de Predicción de Salto emplea un esquema de 2 bits para predecir si un salto debe ser tomado o no.

La tabla tiene 16 entradas, que se corresponden con los 4 últimos bits de la posición en memoria de la instrucción de salto.

El esquema de funcionamiento del algoritmo de 2 bits puede verse en el siguiente dibujo, donde se indica si el salto se toma o no, y las transiciones de estado se deben a si se ha acertado con la última predicción o no:


Reorder Buffer

Estructura que permite la ejecución fuera de orden (out of order) conservando el orden de graduación (commit) de las instrucciones.
El ROB tiene tantas entradas como la suma de las entradas de todas las ER.

Campos

 Nº: Número de entrada en el ROB
 Inst.: Identificador de la instrucción
 Destino: Número de registro destino de la instrucción
 Valor: Resultado de la instrucción
 Direc.: Dirección con la que opera la instrucción (si corresponde)
 Etapa: Etapa actual de la instrucción (ISSUE, EXECUTE, WRITERESULT, COMMIT)


Estaciones de Reserva

Estructura en la que permanecen las instrucciones mientras esperan por sus operandos o se ejecutan en la U. F. correspondiente.
Tienen tantas entradas como una más que el número de etapas de la U.F. correspondiente multiplicada por el número de U.F. de ese tipo que haya.

Campos

 Inst.: Identificador de la instrucción
 Qj: Disponibilidad del primer operando. -1 indica que el valor se encuentra en Vj; otro valor indica la posición del ROB donde se está procesando el operando.
 Vj: Valor del primer operando si (Qj = -1).
 Qk: Disponibilidad del segundo operando. -1 indica que el valor se encuentra en Vk; otro valor indica la posición del ROB donde se está procesando el operando.
 Vk: Valor del segundo operando si (Qk = -1).
 A: Dirección de memoria
 ROB: Posición del ROB donde está esta instrucción


ALU Cálculo Direcciones

La ALU de Cálculo de Direcciones es una U.F. especial de la máquina Superescalar que se encarga únicamente del cálculo de la dirección de una instrucción de memoria, tanto LOADS como STORES.


Máquina VLIW

Características

 Hardware extremadamente simple

 Emisión de una instrucción larga por ciclo

 La instrucción tiene tantas operaciones y de igual tipo que el número de UF que haya.

 Emplea operaciones predicadas.

Componentes

 NaT (GPR): Bits de NaT (Not a Thing). Se ponen a TRUE cuando el registro de propósito general asociado es destino de una operación de LOAD que tuvo un fallo de caché.

 NaT (FPR): Bits de NaT (Not a Thing). Se ponen a TRUE cuando el registro de punto flotante asociado es destino de una operación de LOAD que tuvo un fallo de caché.

 Reg. Pred.: Registros de Predicado.

 U.F.: Unidades Funcionales

NOTA: En la máquina VLIW se denomina "operación" a las instrucciones del código secuencial (ADDI, LF...). En general, se entenderá por "instrucción" la instrucción larga compuesta de operaciones.


NaT (GPR y FPR)

Cada registro (FP o GP) lleva asociado un campo NaT (Not A Thing). Este campo indica, cuando se pone a VERDADERO,  que el registro asociado es destino de una operación de LOAD que tuvo un fallo de caché.


Registros de Predicado

Los Registros de Predicado son unos registros booleanos que se asocian con todas las operaciones de la máquina VLIW para implementar los mecanismos de Predicación de Operaciones. Si un Registro de Predicado asociado a una operación toma un valor FALSO implica la anulación de la ejecución de la operación.

Se dispone de 64 registros denotados por p0, p1, ..., p63.

El Registro de Predicado p0 siempre tiene como valor VERDADERO. Se emplea asociado con aquellas operaciones que no llevan Predicación explícita.


Predicación de Operaciones

La Predicación de Operaciones es un mecanismo que permite ejecutar las operaciones de las dos ramas de un Branch simultáneamente para aprovechar los recursos de la máquina.
La Predicación se realiza asociando con el salto dos Registros de Predicado: un registro que se activará si el salto es tomado (Pred. Verdadero) y un registro que se activará si el salto no es tomado (Pred. Falso).
Todas las operaciones llevan un Registro de Predicado asociado. Este registro se emplea para determinar si la instrucción se ejecuta o no. Cuando el salto es evaluado, se anulan aquellas operaciones que correspondan a la rama no tomada del salto.


Teclado

Teclas de uso general

Ctrl + A: Abrir un nuevo fichero de código secuencial
Alt + F4: Salir
Ctrl + B: Ver Bloques Básicos
Alt + F2: Configurar Superescalar
Alt + F3: Configurar VLIW
Ctrl + F: Establecer % de fallos de caché de datos
F1: Ayuda

Teclas para ejecución de simulación

F2: Seleccionar máquina Superescalar
F3: Seleccionar máquina VLIW
F9: Iniciar ejecución continua
F7: Pausa
F8: Paso a Paso
F6: Parar
Alt + F5: Ver memoria
Alt + F6: Ver Registros de Propósito General
Alt + F7: Ver Registros de Punto Flotante


Referencias

Se incluyen a continuación una serie de documentos de interés:

Documentos

[1] Abnous A., Architectural Design and Analysis of a VLIW Processor, M.S. Thesis, University of California, Irvine, 1991
[2] Colwell R.P., Nix R.P., O'Donnell J.J., Papworth D.B., Rodman P.K., A VLIW Architecture for a Trace Scheduling Compiler, IEEE Transactions on Computers, vol. 37, nº 8, págs . 967-979, Agosto 1988
[3] Hennesy J.L., Patterson D.A., Computer Architecture: A Quantitative Approach (3rd edition), Morgan Kaufmann, 2003
[4] Holm J. G., Evaluation Of Some Superscalar And VLIW Processor Designs, M.S. Thesis University of Illinois, 1992
[5] Huck J., Morris D., Ross J., Knies A., Mulder H., Zahir R., Introducing the IA-64 Architecture, IEEE MICRO, Sept-Oct 2000
[6] Yeager K.C., The MIPS R10000 Superscalar Microprocessor, IEEE Micro, vol. 16, nº. 2, págs. 28-40, Abril 1996.
[7] Muchnik S. Advanced Compiler Design & Implementation, Morgan Kaufmann, 1997
[8] Patel S.J., Trace Cache Design for Wide-Issue Superscalar Processors, PhD Thesis, The University of Michigan, 1999
[9] Rau B.R., Dynamically Scheduled VLIW Processors, Proc. MICRO-26, IEEE Press, 1993
[10] Shen J., Abraham J. A., Verification of Processor Microarchitectures, En Proc. IEEE VLSI Test Symposium, páginas 189-194, 1999
[11] Sima D., Fountain T., Kacsuk P., Advanced Computer Architectures, A Design Space Approach, Addison-Wesley, 1998
[12] Smith J. E., Sohi G. S., The Microarchitecture of Superscalar Processors, Proc. of the IEEE, Diciembre 1995
[13] Zima H.P., Chapman B.M., Supercompilers for Parallel and Vector Computers, ACM Press Frontier Series/Addison-Wesley, 1990

Otros simuladores

[sim1] Edler J., Hill M., Dinero IV: Trace-Driven Uniprocessor Cache Simulator, Univ. of Wisconsin Computer Sciences
[sim2] Lopez P., Calpé R., WinDLXV, Universidad Politécnica de Valencia
[sim3] Texas Instruments, Simulador para la familia de procesadores TMS320C6xxx, 2001
[sim4] Wolf M., Wills L., SATSim: A Superscalar Architecture Trace Simulator Using Interactive Animation, Workshop on Computer Architecture Education, Junio 2000


Historial

v1.1 06/07/2004

 Añadidas opciones de menú Cargar/Crear código VLIW en menú principal
 Añadido menú emergente en ventana de edición de códigos VLIW
 Corregido bug tras abrir un fichero de código secuencial incorrecto que no permitía abrir ningún otro fichero
 Corregido bug que no permitía hacer uso de la tecla 'supr' para borrar una operación de una instrucción larga


Contactar con el autor

Como cualquier programa, SIMDE puede contener errores. Normalmente cuando uno hace un programa no piensa en darle a esa secuencia de pasos que a ti, querido usuario, te ha dado por probar.

Así que para todos esos fallos que vayas encontrando, así como cualquier sugerencia acerca de ampliaciones, mejoras o cambios en el simulador puedes ponerte en contacto conmigo por correo electrónico en ivan@cyc.ull.es.

Iván Castilla Rodríguez

Grupo de Computadoras y Control
Universidad de La Laguna
La Laguna, Tenerife


Bloque Básico

Los bloques básicos son fragmentos de código que tienen una única entrada y una única salida, de tal manera que sus instrucciones se ejecutan secuencialmente.


Desenrollado de bucles

Técnica consistente en replicar el cuerpo de un bucle varias veces. De esta manera se incrementa el número de operaciones disponibles y se puede aprovechar mejor el ILP. Además disminuye la penalización de las operaciones de salto, al disminuir su frecuencia en el código.

// Bucle original
LOOP:
LF 	F1 (R2)
ADDF	F1 F1 F0
DADDUI 	R2 R2 #1
BNE	R2 R5 LOOP

// Bucle desenrollado (2 iteraciones en 1)
LOOP:
LF 	F1 (R2)
ADDF	F1 F1 F0
LF 	F2 1(R2)
ADDF	F2 F2 F0
DADDUI 	R2 R2 #2
BNE	R2 R5 LOOP


Software-Pipelining

Técnica de reorganización de bucles, de tal manera que en cada iteración se construye con operaciones elegidas de distintas iteraciones del bucle original.

// Bucle original
LOOP:
LF 	F1 (R2)
ADDF	F2 F1 F0
SF	F2 (R2)
DADDUI 	R2 R2 #1
BNE	R2 R5 LOOP

// Nuevo bucle (faltan los códigos inicial y final)
LOOP:
// SF pertenece a dos iteraciones antes
SF 	F2 (R2)
// ADDF pertenece a una iteración anterior
ADDF	F2 F1 F0
// LF es de esta iteración
LF 	F1 2(R2)
DADDUI 	R2 R2 #1
BNE	R2 R5 LOOP