2.1 introducción - utmmixteco.utm.mx/~merg/ac/pdfs/unit_2_part_1.pdf · 2009-12-16 · esta...

19
UNIDAD 2: Instrucciones: el lenguaje de las computadoras. 2.1 Introducción Para comandar una computadora se le debe “hablar” en su lenguaje. Las palabras del lenguaje de una máquina son llamadas instrucciones, y su vocabulario es llamado repertorio de instrucciones. En esta sección se expone el repertorio de instrucciones de una computadora real, considerando una forma entendible para los humanos (ensamblador) y una forma entendible por la computadora (código máquina). Podría pensarse que los lenguajes de máquina son tan diversos como los lenguajes de los humanos, sin embargo no es así, los lenguajes de máquina son muy similares entre sí; esto se debe a que todas las computadoras son construidas con tecnologías de hardware basadas en principios fundamentales similares y por que hay unas cuantas operaciones básicas que todas las máquinas deben proporcionar. Más aún, los diseñadores de computadoras tienen una meta común: Encontrar un lenguaje que haga fácil la construcción del hardware y el compilador; mientras se maximiza el rendimiento y se minimiza el costo. Esta meta ha sido honrada a lo largo del tiempo; la siguiente cita fue escrita antes de que fuera posible adquirir una computadora y es tan cierta actualmente, como lo fue en 1947: Es fácil ver por métodos lógicos formales que existen ciertos [repertorios de instrucciones] que son en abstracto adecuados para controlar y causar la ejecución de cualquier secuencia de operaciones. . . . Las consideraciones realmente decisivas desde el punto de vista actual, en seleccionar un [repertorio de instrucciones], son más de naturaleza práctica: La simplicidad del equipo demandado por el [repertorio de instrucciones], y la claridad de su aplicación a problemas realmente importantes junto con la velocidad del manejo de esos problemas. Burks, Goldstine, y von Neumann, 1947 La “simplicidad del equipo” es una consideración tan valiosa para las máquinas actuales como lo fue en los 50’s. La meta de este capítulo es mostrar un repertorio de instrucciones que siga este consejo, mostrando como éste es representado en hardware y su relación con los lenguajes de alto nivel. El repertorio de instrucciones bajo estudio es de una arquitectura MIPS, usado por NEC, Nintendo, Silicon Graphics, y Sony; entre otros. Y es un repertorio de instrucciones típico diseñado en los 80’s. 2.2 Operaciones y operandos. Toda computadora debe realizar operaciones aritméticas. La notación en el lenguaje ensamblador MIPS Add a, b, c Instruye a la computadora a sumar las dos variables b y c, y colocar la suma en a.

Upload: others

Post on 02-Apr-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

UNIDAD 2: Instrucciones: el lenguaje de las computadoras. 2.1 Introducción Para comandar una computadora se le debe “hablar” en su lenguaje. Las palabras del lenguaje de una máquina son llamadas instrucciones, y su vocabulario es llamado repertorio de instrucciones. En esta sección se expone el repertorio de instrucciones de una computadora real, considerando una forma entendible para los humanos (ensamblador) y una forma entendible por la computadora (código máquina). Podría pensarse que los lenguajes de máquina son tan diversos como los lenguajes de los humanos, sin embargo no es así, los lenguajes de máquina son muy similares entre sí; esto se debe a que todas las computadoras son construidas con tecnologías de hardware basadas en principios fundamentales similares y por que hay unas cuantas operaciones básicas que todas las máquinas deben proporcionar. Más aún, los diseñadores de computadoras tienen una meta común: Encontrar un lenguaje que haga fácil la construcción del hardware y el compilador; mientras se maximiza el rendimiento y se minimiza el costo. Esta meta ha sido honrada a lo largo del tiempo; la siguiente cita fue escrita antes de que fuera posible adquirir una computadora y es tan cierta actualmente, como lo fue en 1947:

Es fácil ver por métodos lógicos formales que existen ciertos [repertorios de instrucciones] que son en abstracto adecuados para controlar y causar la ejecución de cualquier secuencia de operaciones. . . . Las consideraciones realmente decisivas desde el punto de vista actual, en seleccionar un [repertorio de instrucciones], son más de naturaleza práctica: La simplicidad del equipo demandado por el [repertorio de instrucciones], y la claridad de su aplicación a problemas realmente importantes junto con la velocidad del manejo de esos problemas.

Burks, Goldstine, y von Neumann, 1947 La “simplicidad del equipo” es una consideración tan valiosa para las máquinas actuales como lo fue en los 50’s. La meta de este capítulo es mostrar un repertorio de instrucciones que siga este consejo, mostrando como éste es representado en hardware y su relación con los lenguajes de alto nivel. El repertorio de instrucciones bajo estudio es de una arquitectura MIPS, usado por NEC, Nintendo, Silicon Graphics, y Sony; entre otros. Y es un repertorio de instrucciones típico diseñado en los 80’s. 2.2 Operaciones y operandos. Toda computadora debe realizar operaciones aritméticas. La notación en el lenguaje ensamblador MIPS Add a, b, c Instruye a la computadora a sumar las dos variables b y c, y colocar la suma en a.

Page 2: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza una sola operación y debe tener tres variables (“variable” en un sentido vago, mas adelante se analizarán los operandos en MIPS). Si se quieren sumar las variables b, c, d y e en la variable a, será necesaria la secuencia:

add a, b, c # La suma de b y c es puesta en a add a, a, d # La suma de b, c y d es puesta en a add a, a, e # La suma de b, c, d y e es puesta en a

Se requiere de tres instrucciones para sumar cuatro variables. Como en todos los ensambladores, cada línea contiene a lo más una instrucción. Los comentarios inician con el símbolo # y terminan al final del renglón. El número natural de operandos para una operación aritmética como la suma es tres, los dos operandos a sumar y el operando donde se colocará el resultado. Por lo que es adecuado que las instrucciones aritméticas cuenten con tres operandos: no más o menos; de acuerdo con la filosofía de mantener un hardware simple, es evidente que el hardware para un número variable de operandos es más complicado que el hardware para un número fijo. Esta situación ilustra el primero de cuatro principios para el diseño de hardware: Principio de diseño 1: La simplicidad favorece la regularidad. En los ejemplos siguientes se muestra la relación que existe entre un lenguaje de alto nivel y el código MIPS.

Ejemplo: Compilando dos asignaciones a código MIPS Este segmento de un programa en C contiene cinco variables a, b, c, d y e:

a = b + c; d = a – e;

La traducción de C al ensamblador MIPS la realiza el compilador correspondiente, mostrar el código MIPS que produciría para estas asignaciones. Respuesta: Una instrucción MIPS opera con dos operandos fuentes y pone el resultado en un operando destino. Para dos asignaciones simples, solo se requiere de dos instrucciones: add a, b, c sub d, a, e

Page 3: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Ejemplo: Compilando una asignación mas compleja Para la siguiente asignación en C:

f = (g + h) – (i + j); ¿Qué produciría el compilador? Respuesta: El compilador separa la asignación y utiliza variables temporales, de manera que el resultado es: add t0, g, h # La variable temporal t0 contiene g + h add t1, i, j # La variable temporal t1 contiene i + j sub f, t0, t1 # f obtiene t0 – t1, que es (g + h) – (i + j) Hasta el momento no se ha puesto atención a los símbolos involucrados en el código MIPS, sin embargo, a diferencia de los lenguajes de alto nivel, los operandos de las instrucciones no pueden ser cualquier variable; mas bien quedan limitados por un número especial de localidades llamadas registros. Los registros son los ladrillos en la construcción de una computadora, se definen durante el diseño del hardware y quedarán visibles al programador cuando la computadora este completada. El tamaño de los registros en la arquitectura MIPS es de 32 bits; los grupos de 32 bits son tan frecuentes que por lo general se les da el nombre de palabra en la arquitectura MIPS. Una principal diferencia entre las variables de un lenguaje de programación y los registros, es el limitado número de registros. MIPS tiene 32 registros, por lo que para una instrucción aritmética se puede elegir entre 32 registros de 32 bits para los tres operandos. La razón del límite en 32 registros se explica con el segundo principio del diseño de hardware. Principio de diseño 2: Si es más pequeño es más rápido. Un número muy grande de registros automáticamente incrementa el tiempo del ciclo de reloj, simplemente por que las señales eléctricas requieren de más tiempo cuando necesitan viajar más lejos. Directivas tales como “Si es mas pequeño es más rápido” no son absolutas; 31 registros no pueden ser mas rápidos que 32. Los diseñadores de hardware deben tomar muy en cuenta este principio y balancear entre el deseo anormal de los programadores por contar con un

Page 4: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

número grande de registros con el deseo de los diseñadores de mantener un ciclo de reloj rápido. Aunque se podrían simplemente considerar los números del 0 al 31 para nombrar a los registros, para no confundirlos con valores constantes, por conveniencia se les antepone el símbolo de pesos ($), de manera que los registros son $0, $1, ..., $31. Además, para simplificar el trabajo del compilador, los registros que correspondan directamente con los nombres de las variables en alto nivel, se nombrarán con $s0, $s1,...; y los registros temporales serán $t1, $t2, $t3,... Esto sólo por convención, en la tabla 2.1 se muestran estas y otras convenciones utilizadas.

Nam e Register num ber Usage$zero 0 the constant value 0$v0-$v1 2-3 values for results and expression evaluation$a0-$a3 4-7 arguments$t0-$t7 8-15 temporaries$s0-$s7 16-23 saved$t8-$t9 24-25 more temporaries$gp 28 global pointer$sp 29 stack pointer$fp 30 frame pointer$ra 31 return address

Tabla 2.1 Convenciones utilizadas aplicadas en el uso de registros.

Puede notarse que el registro $0 siempre contendrá el valor 0, este convención es bastante útil cuando se realizan comparaciones con cero o brincos condicionales.

Ejemplo: Uso de registros. Se repite el ejemplo anterior, pero al utilizar los nombres de los registros en el código ensamblador.

f = (g + h) – (i + j); ¿Qué produciría el compilador? Respuesta: Suponiendo que las variables f, g, h, i y j se asocian con los registros $s0, $s1, $s2, $s3 y $s4, respectivamente. add $t0, $s1, $s2 # El registro $t0 contiene $s1+ $s2 add $t1, $s3, $s4 # El registro $t1 contiene $s3+ $s4 sub $s0, $t0, $t1 # f obtiene $t0 – $t1, que es (g + h) – (i + j)

Page 5: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Los lenguajes de programación usan variables simples que se asocian directamente con registros; sin embargo también utilizan estructuras de datos un poco más complejas como es los arreglos; y es imposible que un arreglo alcance dentro de los registros del procesador.

Memoria

Entrada

SalidaProcesador

Control

Caminode losdatos

Fig. 2.1 Cinco componentes clásicos de una computadora

Recordando los cinco elementos clásicos de la computadora (que se repite en la figura 2.1, por conveniencia), se observa que debido al número limitado de registros, el lugar mas adecuado para las estructuras de datos es la memoria. Sin embargo, puesto que las instrucciones aritméticas solo se realizan con los operandos en registros, la arquitectura MIPS debe incluir algunas instrucciones que permitan la transferencia de datos de memoria a registros y viceversa. La memoria puede ser considerada como un arreglo unidimensional, grande, con las direcciones actuando como índices en el arreglo, iniciando en la 0. Por ejemplo, en la figura 2.2, la dirección del tercer dato en memoria es 2 y su valor es Memoria [2] = 10.

Fig. 2.2 Direcciones de Memoria y su contenido en algunas localidades

La instrucción que mueve datos desde la memoria a un registro se le conoce como carga, y su formato es:

lw $s0, 100 ( $s1 ) que significa $s0 = Memoria[$s1+ 100 ]

lw es el nombre de la instrucción (load word), el primer registro que aparece es el que será cargado ($s0, en este caso), luego se incluye una constante (100, en este caso) la cual se

Page 6: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

considera como un desplazamiento (offset) y finalmente entre paréntesis aparece otro registro ($s1, en este caso), el cual es conocido como registro base. La dirección de la palabra a cargar se forma sumando el valor del registro base con el desplazamiento.

Ejemplo: Carga de memoria. Para la siguiente asignación en C:

g = h + A[8]; ¿Qué produciría el compilador? Suponiendo que el comienzo del arreglo A se encuentra en el registro $s0, y que las variables g y h se asocian con los registros: $s1 y $s2, respectivamente. Respuesta: Primero se debe tener acceso a la memoria para la lectura del dato: lw $t0, 8( $s0) # El registro $t0 contiene A[8] Ahora ya es posible realizar la suma: add $s1, $s2, $t0 # g = h + A[8] Los compiladores son los que se encargan de asociar las estructuras de datos con la memoria. Por lo que el compilador debe poder colocar la dirección adecuada en las instrucciones de transferencias. Puesto que 8 bits (1-byte) son útiles en muchos programas, la mayoría de computadoras conservan el direccionamiento por bytes individuales. Por lo que el direccionamiento por palabras se refiere a la lectura de un conjunto de 4 bytes. Esto significa que las direcciones secuenciales de palabras deben diferir en 4. En la figura 2.2 se mostraron a los datos con direcciones continuas, sin embargo, puesto que se están considerando palabras (de 32 bits), la distribución correcta de los datos sería la que se muestra en la figura 2.3. Debido a que las memorias organizan a los datos por bytes, cuando se manejan arreglos de palabras se afecta a los índices de los mismos, entonces el compilador debe calcular adecuadamente la dirección del dato que será transferido. En el último ejemplo, para que se haga la lectura correcta del elemento 8 del arreglo A, el desplazamiento debe multiplicarse por 4, de manera que a $s0 se le sume 32 (8x4), así se seleccionará al dato A[8] y no a A[8/4].

Page 7: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Fig. 2.3 Direccionamiento por palabras.

La instrucción complementaria a la carga se llama almacenamiento (store), para transferir un dato desde un registro a la memoria. Su formato es similar al de las instrucciones de carga:

sw $s0, 100 ( $s1 ) que significa Memoria[$s1+ 100 ]=$s0 sw es el nombre de la instrucción (store word).

Ejemplo: Carga y Almacenamiento. Para la siguiente asignación en C:

A[12] = h + A[8]; ¿Qué produciría el compilador? Suponiendo que el comienzo del arreglo A se encuentra en el registro $s0, y que la variable h se asocia con el registro $s1: Respuesta: Primero se debe acceder a la memoria para la carga del dato: lw $t0, 32( $s0) # El registro $t0 contiene A[8] Ahora ya es posible realizar la suma: add $t0, $s1, $t0 # El registro $t0 contiene h + A[8] Por último se realiza el almacenamiento: sw $t0, 48( $s0) # A[12]= h + A[8] Los índices del arreglo (8 y 12) se deben multiplicar por 4 para obtener las direcciones adecuadas de los datos en memoria.

Page 8: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Ejemplo: Usando una variable como índice de un arreglo. La siguiente asignación utiliza a la variable i como índice del arreglo A:

g = h + A[i]; ¿Qué producirá el compilador? Suponiendo que el comienzo del arreglo A se encuentra en el registro $s0, y que las variables g, h e i se asocian con los registros: $s1, $s2 y $s3, respectivamente. Respuesta: Antes de accesar a la memoria se debe obtener la dirección adecuada del dato a leer, puesto que solo se han considerado instrucciones de suma, primero se obtendrá i x 4, realizando i + i = 2i, y luego 2i + 2i = 4i: add $t0, $s3, $s3 # $t0 = i + i = 2i add $t0, $t0, $t0 # $t0 = 2i + 2i = 4i La carga se hace con la instrucción: add $t0, $t0, $s0 # $t0 tiene la dirección de A[i]

lw $t1, 0( $t0) # $t1 = A[i] Finalmente se realiza la suma: add $s1, $s2, $t1 # g = h + A[i] Muchos programas tienen más variables que registros en el procesador. En consecuencia, el compilador intenta mantener a las variables más usadas en registros y el resto en memoria, usando cargas y almacenamientos para mover variables entre registros y memoria. El proceso de poner a las variables menos usadas (o aquellas que se usarán posteriormente) en memoria se conoce como derramamiento de registros (spilling registers). El principio de hardware que relaciona el tamaño con la velocidad sugiere que la memoria debe ser mas lenta que los registros porque el tamaño del conjunto de registros es menor que el de la memoria. El acceso a los datos es más rápido si los datos están en registros. Y los datos son más útiles cuando están en registros por que una instrucción aritmética se aplica sobre dos registros, mientras que los accesos a memoria solo manipulan un dato. En conclusión, los datos en los registros en MIPS toman un menor tiempo y tienen una productividad más alta que los datos en la memoria. Para aumentar el rendimiento, los compiladores MIPS deben usar los registros eficientemente.

Page 9: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

2.3 Representación de instrucciones. Hasta el momento se han considerado algunas instrucciones MIPS compuestas de un nombre (nemotécnico) y una serie de operandos; sin embargo dentro de la computadora las instrucciones se almacenan en memoria como pequeños capacitores cargados o descargados y se transfieren entre dispositivos como señales eléctricas con niveles de voltajes altos (5 volts) y bajos (0 volts). Por lo que son suficientes dos símbolos para la representación de las instrucciones. Un sistema numérico con dos símbolos es el sistema binario, por eso se utiliza para la representación de las instrucciones. Sólo hemos considerado 2 tipos de instrucciones, aritméticas y de transferencia de datos, si las comparamos podremos notar que en ambos casos existen tres operandos, en el caso de las instrucciones aritméticas los tres operandos son registros (y como son 32 registros, con 5 bits es suficiente su representación) y para las transferencias de datos dos operandos son registros y el tercero es una constante, es evidente que no es posible disponer solo de 5 bits para el valor de la constante, puesto que su valor sería muy limitado. Lo que implica que si se quiere conservar el mismo formato para ambas instrucciones, estas tendrían diferentes tamaños. Esto da pie al tercer principio de diseño: Principio de diseño 3: Un buen diseño demanda compromisos. Los diseñadores de MIPS enfrentaron el problema de decidir si mantenían a todas las instrucciones del mismo tamaño, generando con ello diferentes formatos de instrucciones o si mantenían el formato ocasionando instrucciones de diferentes tamaños. Se comprometieron con el primer punto y buscando regularidad con el tamaño de los datos, todas las instrucciones en MIPS son de 32 bits. De manera que se tienen diferentes formatos, las instrucciones aritméticas son del Tipo-R por que solo se aplican sobre registros. El formato para las instrucciones Tipo-R es:

op rs rt rd shamt funct6 bits 5 bits 5 bits 5 bits 5 bits 6 bits

El significado para cada uno de los campos es: op: Operación básica de la instrucción, tradicionalmente llamado opcode. Su valor es 0

en el caso de las operaciones aritméticas. rs: El primer operando fuente. rt: El segundo operando fuente. rd: El registro destino, obtiene el resultado de la operación. shamt: Cantidad de desplazamiento (shift amount), solo se aplica a las instrucciones de

desplazamiento, aquí su valor será 0 (se revisa mas adelante). funct: Función, selecciona una variante de la operación, por ejemplo, la suma y resta

ambas son operaciones aritméticas, pero realizan diferentes operaciones. Su valor es de 32 para la suma y 34 para la resta.

Page 10: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Las instrucciones lw y sw son del tipo-I, por que incluyen una constante (dato inmediato). El formato para las instrucciones del tipo-I es:

op rs rt inmediato6 bits 5 bits 5 bits 16 bits

En este caso tenemos: op: Su valor es 35 para las cargas y 43 para los almacenamientos. rs: Registro base para la dirección de memoria. rt: Registro a ser cargado o almacenado. inmediato: Constante que corresponde al desplazamiento.

Ejemplo: Trasladando a código máquina. ¿Cuál es el código máquina de la instrucción: add $t0, $s1, $s2? Respuesta: Tomando como referencia la tabla 1, el registro $t0 es el 8 , $s1 es el 17 y $s2 es el 18. De manera que la representación en decimal de esta instrucción es:

0 17 18 8 0 32 Y su representación binaria corresponde a:

000000 10001 10010 01000 00000 100000

6 bits 5 bits 5 bits 5 bits 5 bits 6 bits

Ejemplo: Trasladando cargas y almacenamientos. La asignación en C: A[12] = h + A[8];

Produjo el siguiente código en ensamblador: lw $t0, 32( $s0) # El registro $t0 contiene A[8] add $t0, $s1, $t0 # El registro $t0 contiene h + A[8] sw $t0, 48( $s0) # A[12]= h + A[8] ¿Cuál es su correspondiente código máquina?

Page 11: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Respuesta: La versión decimal del código máquina es:

35 16 8 32

0 17 8 8 0 32

43 16 8 48 Para obtener los números a los que corresponden los registros, puede usarse la tabla 2.1, la versión binaria del código corresponde a:

100011 10000 01000 0000000000100000

101011 10000 01000 0000000000110000

000000 10001 01000 01000 00000 100000

Actualmente las computadoras se construyen bajo dos principios clave:

1. Las instrucciones se representan como números. 2. Los programas pueden ser almacenados en memoria para ser leídos o escritos al

igual que los números. Estos principios permiten el concepto del programa almacenado, en la figura 2.4 se muestra la potencialidad de este concepto, específicamente la memoria puede contener el código fuente para un programa editor, el correspondiente código máquina compilado, el texto que el programa compilado está usando, y también al compilador que generó el código máquina.

Fig. 2.4 El concepto del programa almacenado,

ilustrado por medio de un ejemplo.

Page 12: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

2.4 Instrucciones para tomar decisiones Lo que distingue a las computadoras de las simples calculadoras es su capacidad para tomar decisiones basadas en los datos de la entrada. En los lenguajes de alto nivel esta acción se realiza con la expresión if algunas veces acompañada con expresiones goto y etiquetas. La arquitectura MIPS cuenta con dos instrucciones de brincos condicionales. La primera: beq registro1, registro2, L1 compara el contenido del registro1 con el del registro2, si son iguales, la siguiente instrucción será la que se encuentra ubicada en la etiqueta L1 (beq – branch if equal). La segunda instrucción es: bne registro1, registro2, L1 y en este caso el brinco se realizará si los contenidos de los registros no son iguales (bne – branch if not equal).

Ejemplo: Compilando una expresión if en un brinco condicional. Para el siguiente código: if ( i == j ) goto L1 f = g + h; L1: f = f – i; Suponiendo que las cinco variables (f a j) se asocian con los registros ($s0 a $s4) ¿Cuál es el código MIPS compilado? Respuesta: beq $s3, $s4, L1 # Se realiza la comparación add $s0, $s1, $s2 # Si no fueron iguales se hace la suma L1: sub $s0, $s0, $s3 # Si ocurrió la igualdad, la siguiente instrucción es la

# resta Los compiladores se encargan de colocar etiquetas cuando éstas no aparecen en el código de alto nivel. Esta es otra ventaja de la escritura de programas en lenguajes de alto nivel. Como un complemento a los brincos condicionales, la arquitectura MIPS cuenta con la instrucción:

j Etiqueta

Page 13: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Por medio de la cual se realiza un salto incondicional, de manera que la siguiente instrucción a ejecutarse es la que se especifica después de la etiqueta.

Ejemplo: Compilando una estructura if-then-else. Para el siguiente código: if ( i == j )

f = g + h; else f = g – h;

Si nuevamente las se asocian con los registros ($s0 a $s4) ¿Cuál es el código MIPS compilado? Respuesta: El compilador generará una serie de etiquetas en forma automática, de acuerdo al flujo del programa. Una opción es la siguiente:

De manera que si i == j se continúa con la suma y luego un salto a la etiqueta exit. En caso de que la igualdad no se cumpla, se hace el salto a la etiqueta else: bne $s3, $s4, Else # Si no son iguales brinca a la etiqueta Else add $s0, $s1, $s2 # Si fueron iguales hace la suma j Exit # y salta a la etiqueta Exit. Else: add $s0, $s1, $s2 # Si no fueron iguales hace la resta Exit: # y termina la decisión. Además de las elecciones entre dos alternativas, con estas instrucciones es posible la ejecución de ciclos repetitivos.

Page 14: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Ejemplo: Compilando un lazo simple. Se tiene el lazo en C: Loop: g = g + A[i] i = i + j;

if( i != h ) goto Loop; Suponiendo que las variables g, h i y j se asocian con los registros $s1, $s2, $s3 y $s4, respectivamente y que el registro base del Arreglo A es $s5 ¿Cuál es el código MIPS compilado? Respuesta: Primero se requiere obtener el valor de A[i] en un registro temporal: Loop: add $t0, $s3, $s3 # $t0 = i + i = 2i add $t0, $t0, $t0 # $t0 = 2i + 2i = 4i add $t0, $t0, $s5 # $t0 contiene la dirección de A[i] lw $t1, 0( $t0) # $t1 = A[i] Luego se realizan las sumas:

add $s1, $s1, $t1 # g = g + A[i] add $s3, $s3, $s4 # i = i + j

Por último se hace el brinco condicional:

bne $s3, $s2, Loop # Si I != j continúa en el lazo. Las sentencias goto son poco usadas por los entendidos con la programación estructurada, pero con estas instrucciones es posible la compilación de los ciclos: while y do-while.

Ejemplo: Compilando un ciclo while. Se tiene el ciclo repetitivo:

while (save[i] == k) i = i + j;

Page 15: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Si las variables i, j y k se asocian con los registros $s3, $s4 y $s5, respectivamente y que el registro base del Arreglo save es $s6 ¿Cuál es el código MIPS compilado? Respuesta: Para que pueda compararse el valor de save[i], debe obtenerse en un registro temporal: Loop: add $t1, $s3, $s3 # $t1 = i + i = 2i add $t1, $t1, $t1 # $t1 = 2i + 2i = 4i add $t1, $t1, $s6 # $t1 contiene la dirección de save[i] lw $t1, 0( $t1) # $t1 = save[i] Ahora es posible comparar a save[i] con k, si son diferentes, termina el ciclo:

bne $t1, $s6, Exit # si save[i] es diferente de k, termina el ciclo. Dentro del ciclo se realiza la suma:

add $s3, $s3, $s4 # i = i + j El ciclo se repite:

j Loop # Salta a la siguiente iteración Exit: La prueba de igualdad o desigualdad para un salto es la mas popular, sin embargo algunas veces es útil evaluar si una variable es menor que otra, por ejemplo en los ciclos repetitivos for, en los cuales se va incrementando (o decrementando) una variable y se continúa en el ciclo mientras sea menor que otra (o mayor que 0). MIPS cuenta con la instrucción slt (set on less than), que compara dos registros y modifica a un tercero de acuerdo con el resultado de la comparación. Por ejemplo: slt $t0, $s1, $s2 Pondrá un 1 en $t0 si $s1 < $s2, en caso contrario, $t0 contendrá 0.

Ejemplo: Prueba de la instrucción slt. ¿Cuál es el código que prueba si una variable a (asociada con $s0) es menor que una variable b (asociada con $s1) y brinca a la etiqueta less si la condición se mantiene? Respuesta:

Page 16: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

slt $t0, $s0, $s1 # $t0 = 1 si a < b y $t0 = 0 en caso contrario bne $t0, $zero, less # $t0 no es igual a 0, brinca a la etiqueta less

Notar que se está aprovechando el hecho de que el registro cero contiene el valor 0. Las estructuras de decisión if-then-else son ampliamente usadas, sin embargo en muchos programas se tiene diferentes alternativas a seguir después de evaluar una expresión. Para ello algunos lenguajes manejan estructuras de decisión múltiple, por ejemplo, la estructura switch-case del lenguaje C (o similares). Se espera que una estructura de este estilo sea más eficiente que múltiples comparaciones individuales. Para conseguirlo, los compiladores deben generar una tabla de direcciones de salto, de manera que se obtenga la dirección destino de la tabla y se realice el salto en forma inmediata. Para tales situaciones, la arquitectura MIPS incluye a la instrucción jr (jump register) la cual realizará un salto incondicional a la dirección contenida en el registro especificado en la instrucción.

Ejemplo: Compilando una estructura switch-case. El siguiente código C selecciona entre cuatro alternativas dependiendo si el valor de k es 0, 1, 2 o 3:

switch ( k ) { case 0: f = i + h; break; /* k = 0 */ case 1: f = g + h; break; /* k = 1 */ case 2: f = g - h; break; /* k = 2 */ case 3: f = i - j; break; /* k = 3 */ }

Suponer que las seis variable f a k corresponden a los registros $s0 al $s5 y que el registro $t2 contiene 4. ¿Cuál es el correspondiente código MIPS? Respuesta: El objetivo es evaluar a la variable k para indexar a la tabla de direcciones, y posteriormente saltar al valor cargado. Pero primero es necesario asegurarse que k está en un caso válido:

slt $t3, $s5, $zero # Prueba si k < 0 bne $t3, $zero, Exit # Si k < 0, termina slt $t3, $s5, $t2 # Prueba si k <4

Page 17: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

beq $t3, $zero, Exit # Si k >= 4, termina Si el valor de k es válido, para que pueda utilizarse como índice, debe multiplicarse por 4 add $t1, $s5, $s5 # $t1 = k + k = 2k add $t1, $t1, $t1 # $t1 = 2k + 2k = 4k Supongamos que existen cuatro palabras secuenciales en memoria que inician en la dirección contenida en $t4 y contienen la dirección correspondiente a las etiquetas L0, L1, L2 y L3. Para obtener la dirección adecuada para el salto se utilizan las instrucciones: add $t1, $t1, $t4 # $t1 = dirección de la tabla_de_saltos[k] lw $t0, 0( $t1) # $t1 = tabla_de_saltos[k] Un salto a registro desviará el flujo del programa a la opción correspondiente:

jr $t0 # salto basado en el registro t0. Las instrucciones que se realizarán en cada caso, de acuerdo con el valor de k son: L0: add $s0, $s3, $s4 # k = 0 => f = i + j j Exit L1: add $s0, $s1, $s2 # k = 1 => f =g + h j Exit L2: sub $s0, $s1, $s2 # k = 2 => f = g - h j Exit L3: sub $s0, $s3, $s4 # k = 3 => f = i – j Exit: # fin del switch-case Resumen: Los operandos en MIPS son:

Page 18: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Las instrucciones consideradas hasta el momento del repertorio MIPS son:

El lenguaje de máquina para las instrucciones consideradas hasta el momento es:

Page 19: 2.1 Introducción - UTMmixteco.utm.mx/~merg/AC/pdfs/Unit_2_Part_1.pdf · 2009-12-16 · Esta notación es rígida, en el sentido que cada instrucción aritmética de MIPS realiza

Tarea 3:

1.- Obtener el código MIPS de la asignación: x[10] = x[11] + c; Suponer que c corresponde al registro $t1 y el arreglo x tiene una dirección base de 4000. 2.- Escriba el código máquina generado para el ejercicio anterior. 3.- Con el ensamblador MIPS, indique la secuencia de instrucciones que evalúe a los registros $s0, $s1 y $s2 y deje el valor del menor en $s3. 4.- Escriba el código máquina generado para el ejercicio 3. 5.- El siguiente código acumula los valores del arreglo A en la variable x: for ( x = 0, i = 0; i < 10; i++ ) x = x + A[i]; ¿Cuál será el código MIPS para este código? Suponga que el comienzo del arreglo A esta en el registro $s3, que el registro $t1 contiene 10, que la variable x se asocia con $s1 y la variable i con $s2. 6.- Transforme la siguiente asignación: c = ( a > b ) ? a : b; a código MIPS. Asocie a, b y c con $s0, $s1 y $s2, respectivamente.