28.01.2015 Views

Programación en ensamblador del MIPS. - Departamento de ...

Programación en ensamblador del MIPS. - Departamento de ...

Programación en ensamblador del MIPS. - Departamento de ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Estructura <strong>de</strong> Computadores<br />

Capítulo 3b: <strong>Programación</strong> <strong>en</strong><br />

<strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.<br />

José Daniel Muñoz Frías<br />

Universidad Pontificia Comillas. ETSI ICAI.<br />

Departam<strong>en</strong>to <strong>de</strong> Electrónica y Automática<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 1<br />

Índice<br />

1. Introducción.<br />

2. Registros disponibles.<br />

3. Operaciones aritméticas.<br />

4. Acceso a memoria.<br />

5. Codificación <strong>en</strong> l<strong>en</strong>guaje máquina.<br />

6. Toma <strong>de</strong> <strong>de</strong>cisiones.<br />

7. Llamadas a funciones.<br />

8. Manejo <strong>de</strong> caracteres.<br />

9. Aritmética.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 2


Introducción<br />

En este tema se va a estudiar <strong>en</strong> <strong>de</strong>talle la<br />

arquitectura <strong>MIPS</strong>. Se estudiará:<br />

• El juego <strong>de</strong> instrucciones.<br />

• El l<strong>en</strong>guaje <strong>en</strong>samblador y la codificación <strong>de</strong><br />

instrucciones.<br />

• Los recursos disponibles.<br />

Cada arquitectura ti<strong>en</strong>e su propio juego <strong>de</strong><br />

instrucciones y su propio <strong>en</strong>samblador, aunque todos<br />

son similares.<br />

El apr<strong>en</strong>dizaje se apoyará con prácticas <strong>de</strong> laboratorio.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 3<br />

En el tema anterior se han estudiado las características que <strong>de</strong>be cumplir un juego <strong>de</strong><br />

instrucciones. En este capítulo se va a mostrar <strong>en</strong> <strong>de</strong>talle el juego <strong>de</strong> instrucciones <strong>de</strong> la arquitectura<br />

<strong>MIPS</strong>, así como las técnicas <strong>de</strong> programación <strong>en</strong> <strong>en</strong>samblador <strong>en</strong> dicha arquitectura.<br />

Como probablem<strong>en</strong>te sabrá, cada procesador ti<strong>en</strong>e su propia arquitectura y su propio l<strong>en</strong>guaje<br />

<strong>en</strong>samblador. Por tanto pue<strong>de</strong> parecer una pérdida <strong>de</strong> tiempo apr<strong>en</strong><strong>de</strong>r un <strong>en</strong>samblador<br />

concreto, ya que éste sólo servirá para programar una arquitectura. No obstante lo anterior no<br />

es cierto por dos razones fundam<strong>en</strong>tales:<br />

• La filosofía <strong>de</strong> programación <strong>en</strong> <strong>en</strong>samblador es idéntica para todas las arquitecturas.<br />

En todas ellas, las operaciones que se pued<strong>en</strong> realizar son muy básicas y es necesario<br />

“bajar” al nivel <strong>de</strong> la máquina.<br />

• Aunque cada arquitectura ti<strong>en</strong>e un juego <strong>de</strong> instrucciones propio, todas las arquitecturas<br />

incorporan una serie <strong>de</strong> instrucciones básicas con funcionalida<strong>de</strong>s muy parecidas.<br />

Por ejemplo todas las arquitecturas incluy<strong>en</strong> la instrucción ADD para realizar una suma.<br />

Las difer<strong>en</strong>cias estarán <strong>en</strong> el número <strong>de</strong> operandos que admit<strong>en</strong> o <strong>en</strong> el nemónico.<br />

Por tanto, una vez que se ha apr<strong>en</strong>dido a programar <strong>en</strong> <strong>en</strong>samblador con una arquitectura,<br />

programar otra es cuestión <strong><strong>de</strong>l</strong> poco tiempo que lleva familiarizarse con ella.<br />

Este tema se basa <strong>en</strong> el capítulo 3 <strong>de</strong> (Patterson y H<strong>en</strong>nessy, 2000).<br />

En el laboratorio se usará el simulador SPIM,<br />

1 disponible <strong>en</strong>:<br />

http://www.cs.wisc.edu/˜larus/spim.html<br />

1 El nombre SPIM es simplem<strong>en</strong>te <strong>MIPS</strong> escrito al revés.


Registros disponibles<br />

<strong>MIPS</strong> dispone <strong>de</strong>:<br />

• 32 registros <strong>de</strong> 32 bits para <strong>en</strong>teros<br />

• 32 registros <strong>de</strong> 32 bits para coma flotante.<br />

• Un contador <strong>de</strong> programa <strong>de</strong> 32 bits<br />

• Dos registros <strong>de</strong> 32 bits para almac<strong>en</strong>ar los<br />

resultados <strong>de</strong> multiplicaciones y divisiones.<br />

Existe una conv<strong>en</strong>ción “software” para el uso <strong>de</strong> los<br />

registros <strong>en</strong>teros.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 4<br />

La primera característica que <strong>de</strong>be conocer un programador sobre una arquitectura es<br />

qué registros están disponibles.<br />

En el caso <strong><strong>de</strong>l</strong> <strong>MIPS</strong>, se dispone <strong>de</strong> un banco <strong>de</strong> registros para almac<strong>en</strong>ar números <strong>en</strong>teros<br />

y otro para almac<strong>en</strong>ar números <strong>en</strong> coma flotante. Ambos bancos constan <strong>de</strong> 32 registros <strong>de</strong><br />

32 bits. En el caso <strong><strong>de</strong>l</strong> banco <strong>de</strong> coma flotante, los registros se pued<strong>en</strong> agrupar <strong>de</strong> dos <strong>en</strong> dos<br />

para utilizarlos <strong>en</strong> operaciones con números <strong>en</strong> doble precisión (64 bits).<br />

A<strong>de</strong>más <strong>de</strong> estos bancos, la arquitectura <strong>MIPS</strong> <strong>de</strong>fine tres registros adicionales: el contador<br />

<strong>de</strong> programa y dos registros llamados Hi y Lo que se utilizan para almac<strong>en</strong>ar el resultado<br />

<strong>de</strong> las operaciones <strong>de</strong> multiplicación y división <strong>en</strong>teras. En el caso <strong>de</strong> la multiplicación, recuer<strong>de</strong><br />

que el producto <strong>de</strong> dos números <strong>de</strong> 32 bits da como resultado un número <strong>de</strong> 64 bits.<br />

De la misma forma, el coci<strong>en</strong>te <strong>de</strong> dos números <strong>de</strong> 32 bits da como resultado un coci<strong>en</strong>te <strong>de</strong><br />

32 bits y un resto también <strong>de</strong> 32 bits.<br />

Aunque para el procesador todos los registros son iguales, existe una conv<strong>en</strong>ción seguida<br />

por todos los programadores para el uso <strong>de</strong> los registros para <strong>en</strong>teros, la cual pasamos a<br />

<strong>de</strong>scribir a continuación.


Registros disponibles<br />

0 zero Constante 0<br />

1 at Reservado para el <strong>en</strong>samblador<br />

2 v0 Evaluación <strong>de</strong> expresiones<br />

3 v1 y retorno <strong>de</strong> resultados<br />

4 a0 Argum<strong>en</strong>tos <strong>de</strong> funciones<br />

··· ··· ···<br />

7 a3<br />

8 t0 Valores temporales<br />

··· ··· La invocada pue<strong>de</strong> modificarlos<br />

15 t7 La invocadora <strong>de</strong>be guardarlos<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 5<br />

En la tabla <strong>de</strong> esta transpar<strong>en</strong>cia y la sigui<strong>en</strong>te se muestran los registros <strong>en</strong>teros <strong><strong>de</strong>l</strong><br />

<strong>MIPS</strong> junto con el uso que se <strong>de</strong>be hacer <strong>de</strong> ellos. Como se dijo antes, para el procesador<br />

todos los registros (excepto el 0) son iguales. Sin embargo para hacer más fácil y efici<strong>en</strong>te<br />

la programación, existe una conv<strong>en</strong>ción <strong>de</strong> uso <strong>de</strong> estos registros que se <strong>de</strong>scribe <strong>en</strong> <strong>de</strong>talle a<br />

continuación:<br />

• El registro zero conti<strong>en</strong>e siempre la constante 0. La utilidad <strong>de</strong> este “registro” se<br />

verá más a<strong><strong>de</strong>l</strong>ante.<br />

• El registro at está reservado para ser usado por el <strong>en</strong>samblador.<br />

• Los registros v0 y v1 se utilizan para evaluar expresiones y para que las funciones<br />

puedan <strong>de</strong>volver sus resultados.<br />

• Los registros a0···a3 se utilizan para pasarle argum<strong>en</strong>tos a las funciones. Si son<br />

necesarios más <strong>de</strong> 4 argum<strong>en</strong>tos (o éstos necesitan más <strong>de</strong> 32 bits) se recurre a la<br />

pila.<br />

• Los registros t0···t7 se utilizan para almac<strong>en</strong>ar valores temporales. Por tanto cualquier<br />

función pue<strong>de</strong> usarlos sin preocuparse <strong>de</strong> guardar su valor anterior. Ahora bi<strong>en</strong>,<br />

si una función necesita algún valor almac<strong>en</strong>ado <strong>en</strong> estos registros ha <strong>de</strong> guardarlo <strong>en</strong><br />

otro sitio (memoria, registros) antes <strong>de</strong> llamar a otra función (la invocada), pues ésta<br />

supondrá que dichos registros sólo conti<strong>en</strong><strong>en</strong> valores inútiles para qui<strong>en</strong> la ha llamado<br />

(la invocadora).


Registros disponibles<br />

16 s0 Salvados por la invocada<br />

··· ··· La invocada <strong>de</strong>be guardarlos<br />

23 s7 antes <strong>de</strong> usarlos<br />

24 t8 Valores temporales<br />

25 t9 I<strong>de</strong>m ant.<br />

26 k0 Reservados para el<br />

27 k1 sistema operativo<br />

28 gp Puntero al área global<br />

29 sp Puntero <strong>de</strong> pila (stack pointer)<br />

30 fp Puntero al bloque <strong>de</strong> activación (frame pointer)<br />

31 ra Dirección <strong>de</strong> retorno (return address)<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 6<br />

• Los registros s0···s7 se utilizan para almac<strong>en</strong>ar variables que <strong>de</strong>b<strong>en</strong> ser preservadas<br />

<strong>en</strong>tre llamadas a funciones. Por tanto, si alguna función necesita usar alguno <strong>de</strong> estos<br />

registros, ha <strong>de</strong> guardar antes su valor (por ejemplo <strong>en</strong> la pila). De esta forma, la<br />

función que usa estos registros no ha <strong>de</strong> preocuparse <strong>de</strong> guardar sus valores antes <strong>de</strong><br />

llamar a otra función.<br />

• Los registros t8 y t9 se utilizan <strong>de</strong> la misma manera que los registros t0···t7.<br />

• Los registros k0 y k1 están reservados para el sistema operativo.<br />

• El registro gp se utiliza para apuntar al área <strong>de</strong> memoria don<strong>de</strong> están los datos <strong><strong>de</strong>l</strong><br />

programa. Su utilidad se verá más a<strong><strong>de</strong>l</strong>ante.<br />

• El registro sp es el puntero <strong>de</strong> la pila (conti<strong>en</strong>e la dirección <strong><strong>de</strong>l</strong> tope <strong>de</strong> la pila).<br />

• El registro fp conti<strong>en</strong>e la dirección <strong>de</strong> la zona <strong>de</strong> la pila <strong>en</strong> la que están guardados<br />

los argum<strong>en</strong>tos y las variables locales <strong>de</strong> la función que no cab<strong>en</strong> <strong>en</strong> los registros.<br />

Esta zona se conoce como bloque <strong>de</strong> activación. Su utilidad es la <strong>de</strong> simplificar el<br />

acceso a estas variables cuando es necesario modificar la pila durante la ejecución <strong>de</strong><br />

la función (por ejemplo durante la evaluación <strong>de</strong> expresiones).<br />

• Por último, el registro ra conti<strong>en</strong>e la dirección a la que <strong>de</strong>be retornar la función invocada<br />

cuando finalice su labor. El funcionami<strong>en</strong>to <strong>de</strong>tallado <strong>de</strong> estos tres últimos<br />

registros se verá cuando se estudie el mecanismo <strong>de</strong> llamada a funciones <strong>de</strong> la arquitectura<br />

<strong>MIPS</strong>.


Operaciones aritméticas<br />

En las sigui<strong>en</strong>tes transpar<strong>en</strong>cias se muestran varios<br />

ejemplos <strong>en</strong> <strong>en</strong>samblador <strong>MIPS</strong> para realizar<br />

operaciones aritméticas.<br />

Se partirá <strong>de</strong> la expresión <strong>en</strong> C para estudiar cómo se<br />

implanta dicha expresión <strong>en</strong> <strong>en</strong>samblador.<br />

Características <strong>de</strong> las operaciones aritméticas <strong>MIPS</strong>:<br />

• Operaciones <strong>de</strong> 3 direcciones.<br />

• Operandos y resultados han <strong>de</strong> estar <strong>en</strong> registros.<br />

• Un operando pue<strong>de</strong> ser una constante <strong>de</strong> 16 bits.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 7<br />

Para estudiar el <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>, se van a introducir sus instrucciones principales<br />

a través <strong>de</strong> ejemplos. En estos ejemplos se partirá <strong>de</strong> un trozo <strong>de</strong> código <strong>en</strong> l<strong>en</strong>guaje C y se<br />

estudiará como se implanta dicho código <strong>en</strong> <strong>en</strong>samblador.<br />

En primer lugar se van a estudiar algunas <strong>de</strong> las instrucciones disponibles <strong>en</strong> la arquitectura<br />

<strong>MIPS</strong> para realizar operaciones aritméticas con números <strong>en</strong>teros. Todas estas instrucciones,<br />

junto con las instrucciones para realizar operaciones lógicas compart<strong>en</strong> tres características<br />

fundam<strong>en</strong>tales:<br />

• Operaciones <strong>de</strong> 3 direcciones. La primera dirección será don<strong>de</strong> se almac<strong>en</strong>e el<br />

resultado y las otras dos los operandos.<br />

• Operandos y resultados han <strong>de</strong> estar <strong>en</strong> registros. Por tanto antes <strong>de</strong> realizar<br />

cualquier operación, si alguno <strong>de</strong> los datos está <strong>en</strong> memoria será necesario cargarlo<br />

<strong>en</strong> un registro.<br />

• Un operando pue<strong>de</strong> ser una constante <strong>de</strong> 16 bits. En estos casos se realiza la operación<br />

<strong>en</strong>tre dicha constante y un registro para almac<strong>en</strong>ar el resultado <strong>en</strong> otro registro.


Operaciones aritméticas<br />

La expresión <strong>en</strong> C:<br />

int a, b, c;<br />

c = a + b;<br />

Se traduce <strong>en</strong> <strong>en</strong>samblador (suponi<strong>en</strong>do la asignación<br />

<strong>de</strong> registros: a->s0, b->s1 y c->s2) como:<br />

add $s2, $s0, $s1<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 8<br />

En este ejemplo, suponemos que las tres variables <strong>en</strong>teras a, b y c han sido situadas por<br />

el compilador <strong>en</strong> los registros s0, s1 y s2 respectivam<strong>en</strong>te (<strong>en</strong> el compilador <strong>de</strong> C <strong><strong>de</strong>l</strong> <strong>MIPS</strong><br />

el tipo int es <strong>de</strong> 32 bits).<br />

La instrucción <strong>de</strong> suma <strong>en</strong> el <strong>MIPS</strong> se repres<strong>en</strong>ta con el nemónico add. A<strong>de</strong>más, tal como<br />

se ha dicho anteriorm<strong>en</strong>te, las instrucciones aritméticas <strong><strong>de</strong>l</strong> <strong>MIPS</strong> son <strong>de</strong> tres direcciones.<br />

Esto implica que siempre realizan la operación <strong>en</strong>tre dos registros, o <strong>en</strong>tre un registro y una<br />

constante <strong>de</strong> 16 bits, y almac<strong>en</strong>an su resultado <strong>en</strong> un registro. En el <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong> se<br />

escribe <strong>en</strong> primer lugar el registro <strong>de</strong>stino <strong><strong>de</strong>l</strong> resultado y a continuación los dos operandos.<br />

La restricción <strong>de</strong> que todas las operaciones aritméticas sean <strong>de</strong> tres direcciones pue<strong>de</strong><br />

parecer caprichosa. Sin embargo dicha restricción está motivada por el <strong>de</strong>seo <strong>de</strong> simplificar la<br />

circuitería, ya que si se quisieran implantar instrucciones con distintos números <strong>de</strong> operandos<br />

se necesitaría circuitería específica para cada uno <strong>de</strong> los casos. Esto se pue<strong>de</strong> resumir <strong>en</strong> uno<br />

<strong>de</strong> los principios <strong>de</strong> diseño hardware:<br />

Principio <strong>de</strong> diseño 1: la uniformidad simplifica el hardware.<br />

Cabe preguntarse cómo se pue<strong>de</strong> realizar la suma <strong>de</strong> más <strong>de</strong> dos variables. En la sigui<strong>en</strong>te<br />

transpar<strong>en</strong>cia se ilustra con otro ejemplo.


Operaciones aritméticas<br />

¿Cómo se traduce <strong>en</strong> <strong>en</strong>samblador la expresión <strong>en</strong> C<br />

int a, b, c, d, e;<br />

a = b + c + d + e;<br />

Suponi<strong>en</strong>do la asignación <strong>de</strong> registros: a->s0, b->s1,<br />

c->s2, d->s3 y e->s4, se necesitan ahora tres<br />

instrucciones:<br />

add $s0, $s1, $s2 # a conti<strong>en</strong>e b+c<br />

add $s0, $s0, $s3 # ahora a vale b+c+d<br />

add $s0, $s0, $s4 # y por fin a es b+c+d+e<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 9<br />

Como se pue<strong>de</strong> apreciar, ahora es necesario sumar 4 variables, pero las instrucciones<br />

aritméticas <strong><strong>de</strong>l</strong> <strong>MIPS</strong> sólo permit<strong>en</strong> sumar dos. Para resolver este problema, se realizan tres<br />

sumas parciales:<br />

1. b+c<br />

2. b+c+d<br />

3. b+c+d+e<br />

Dichas sumas parciales se han ido almac<strong>en</strong>ando <strong>en</strong> el registro asignado a la variable a (s0).<br />

En este ejemplo se ilustran dos cosas nuevas:<br />

• Un mismo registro pue<strong>de</strong> ser a la vez fu<strong>en</strong>te y <strong>de</strong>stino. Así, <strong>en</strong> la segunda instrucción<br />

se está sumando s0 (que conti<strong>en</strong>e ya b+c) con d y el resultado se vuelve a guardar <strong>en</strong><br />

s0.<br />

• El texto que aparece a la <strong>de</strong>recha <strong><strong>de</strong>l</strong> carácter # es un com<strong>en</strong>tario y por tanto es<br />

ignorado por el <strong>en</strong>samblador. A difer<strong>en</strong>cia <strong>de</strong> C no es necesario especificar el final<br />

<strong><strong>de</strong>l</strong> com<strong>en</strong>tario, ya que éste acaba al final <strong>de</strong> la línea. Si se <strong>de</strong>sean más líneas <strong>de</strong><br />

com<strong>en</strong>tario será necesario usar caracteres # adicionales <strong>en</strong> cada línea.<br />

También es necesario <strong>de</strong>stacar que cada línea pue<strong>de</strong> cont<strong>en</strong>er como mucho una instrucción<br />

<strong>de</strong> <strong>en</strong>samblador.


Operaciones aritméticas<br />

¿Cómo se traduce <strong>en</strong> <strong>en</strong>samblador la expresión <strong>en</strong> C<br />

int a, b, c, d, e;<br />

a = (b + c) - (d + e);<br />

Se realiza la asignación <strong>de</strong> registros: a->s0, b->s1,<br />

c->s2, d->s3 y e->s4.<br />

add $t0, $s1, $s2<br />

add $t1, $s3, $s4<br />

sub $s0, $t0, $t1<br />

# se usa t0 para b+c<br />

# se usa t1 para d+e<br />

# s0 vale ahora t0-t1<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 10<br />

Para evaluar la expresión a = (b + c) - (d + e) es necesario evaluar <strong>en</strong> primer lugar<br />

las expresiones <strong>en</strong>tre paréntesis y a continuación restar ambos resultados. Para almac<strong>en</strong>ar los<br />

resultados <strong>de</strong> las expresiones <strong>en</strong>tre paréntesis se usan variables temporales, ya que lo más<br />

probable es que no necesitemos nunca más dichos resultados. Se han elegido para ello los<br />

registros temporales t0 y t1.<br />

Otra novedad <strong>de</strong> este ejemplo es la instrucción sub, la cual resta el tercer argum<strong>en</strong>to <strong><strong>de</strong>l</strong><br />

segundo y lo almac<strong>en</strong>a <strong>en</strong> el primero, es <strong>de</strong>cir:<br />

sub $s0, $t0, $t1<br />

hace que s0 = t0 - t1.<br />

Ejercicio<br />

Modifique el programa anterior para evitar el uso <strong>de</strong> los dos registros temporales. Pista:<br />

Pue<strong>de</strong> usar el registro s0 para ir almac<strong>en</strong>ando los resultados parciales.


Acceso a memoria<br />

Es necesario acce<strong>de</strong>r a memoria para usar:<br />

• Vectores y matrices.<br />

• Estructuras <strong>de</strong> datos.<br />

• Variables que no están <strong>en</strong> registros.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 11<br />

En los ejemplos mostrados hasta ahora se ha supuesto que todas las variables involucradas<br />

<strong>en</strong> las operaciones estaban almac<strong>en</strong>adas <strong>en</strong> los registros <strong><strong>de</strong>l</strong> procesador. Ahora bi<strong>en</strong>, esto<br />

no siempre es así. Todos los l<strong>en</strong>guajes <strong>de</strong> programación soportan tipos <strong>de</strong> datos complejos<br />

que no pued<strong>en</strong> ser almac<strong>en</strong>ados d<strong>en</strong>tro <strong>de</strong> unos cuantos registros <strong>de</strong> 32 bits. Ejemplos claros<br />

son los vectores, las matrices y las estructuras <strong>de</strong> datos.<br />

A<strong>de</strong>más, <strong>en</strong> muchas ocasiones los programas necesitan manejar más variables <strong>de</strong> las que<br />

pued<strong>en</strong> almac<strong>en</strong>arse <strong>en</strong> los registros. En estos casos no queda más remedio que mant<strong>en</strong>er<br />

algunas variables <strong>en</strong> memoria y traerlas a los registros temporales cuando necesitemos operar<br />

con ellas.<br />

Por último, antes <strong>de</strong> po<strong>de</strong>r usar una variable es necesario cargarla <strong>en</strong> un registro.<br />

En consecu<strong>en</strong>cia, la arquitectura <strong>MIPS</strong>, al igual que todas las <strong>de</strong>más, dispone <strong>de</strong> instrucciones<br />

<strong>de</strong> transfer<strong>en</strong>cia <strong>de</strong> datos que permit<strong>en</strong> cargar un valor <strong>de</strong>s<strong>de</strong> la memoria a un registro<br />

y para almac<strong>en</strong>ar un registro <strong>en</strong> la memoria.


Acceso a memoria. Organización<br />

El bus <strong>de</strong> datos <strong><strong>de</strong>l</strong> <strong>MIPS</strong> es <strong>de</strong> 32 bits.<br />

Es posible direccionar cada byte individualm<strong>en</strong>te.<br />

Dirección <strong>de</strong> palabra =<br />

dir. byte más significativo:<br />

Arquitectura big <strong>en</strong>dian<br />

Dirección <strong>de</strong> palabra =<br />

múltiplo <strong>de</strong> 4<br />

Restricción <strong>de</strong> alineación<br />

Dir<br />

Palabra<br />

8<br />

4<br />

0<br />

msB lsB<br />

8 9 A B<br />

4 5 6 7<br />

0 1 2 3<br />

Dir. Byte<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 12<br />

Antes <strong>de</strong> estudiar <strong>en</strong> <strong>de</strong>talle las instrucciones <strong>de</strong> transfer<strong>en</strong>cia <strong>de</strong> datos <strong><strong>de</strong>l</strong> <strong>MIPS</strong>, es<br />

conv<strong>en</strong>i<strong>en</strong>te ver cómo está estructurada su memoria.<br />

Los procesadores <strong>MIPS</strong> ti<strong>en</strong><strong>en</strong> un bus <strong>de</strong> datos <strong>de</strong> 32 bits, por lo que <strong>en</strong> cada acceso a<br />

memoria se lee una palabra <strong>de</strong> 32 bits. Como se ha dicho antes, <strong>de</strong>bido <strong>en</strong>tre otras cosas a<br />

que un carácter ocupa un byte, es necesario po<strong>de</strong>r acce<strong>de</strong>r a éstos individualm<strong>en</strong>te. Por ello,<br />

aunque la memoria física está organizada <strong>en</strong> palabras <strong>de</strong> 32 bits, <strong>de</strong>s<strong>de</strong> el punto <strong>de</strong> vista lógico<br />

(o <strong><strong>de</strong>l</strong> programador), la memoria ha <strong>de</strong> estar organizada <strong>en</strong> bytes. Para ello, tal como pue<strong>de</strong><br />

apreciarse <strong>en</strong> la figura, cada palabra está “dividida” <strong>en</strong> 4 bytes, cada uno con su dirección<br />

para po<strong>de</strong>r acce<strong>de</strong>r a él individualm<strong>en</strong>te. Las direcciones <strong>de</strong> palabra <strong>en</strong> este caso coincid<strong>en</strong><br />

con la <strong><strong>de</strong>l</strong> byte más significativo. Se dice <strong>en</strong>tonces que la arquitectura es big <strong>en</strong>dian. Otros<br />

ejemplos <strong>de</strong> arquitecturas big <strong>en</strong>dian son: IBM 360/370, Motorola 68k y Sparc. Existe otra<br />

alternativa, seguida fundam<strong>en</strong>talm<strong>en</strong>te por la arquitectura IA-32 <strong>en</strong> la que la dirección <strong>de</strong><br />

palabra coinci<strong>de</strong> con el byte m<strong>en</strong>os significativo. En este caso se dice que la arquitectura es<br />

little <strong>en</strong>dian.<br />

El que una arquitectura sea big <strong>en</strong>dian o little <strong>en</strong>dian es más o m<strong>en</strong>os transpar<strong>en</strong>te al<br />

programador. Sólo cuando éste ti<strong>en</strong>e que examinar la memoria <strong>en</strong> busca <strong>de</strong> números <strong>de</strong> más <strong>de</strong><br />

8 bits ha <strong>de</strong> t<strong>en</strong>er <strong>en</strong> cu<strong>en</strong>ta su organización. Ahora bi<strong>en</strong>, este tema es crítico si se intercambian<br />

datos <strong>en</strong>tre dos arquitecturas con distintas “<strong>en</strong>dianess”.<br />

Por último, cabe <strong>de</strong>stacar que <strong>en</strong> la arquitectura <strong>MIPS</strong> las direcciones <strong>de</strong> palabra <strong>de</strong>b<strong>en</strong><br />

<strong>de</strong> ser siempre múltiplos <strong>de</strong> 4. Esto es lo que se conoce como restricción <strong>de</strong> alineación.<br />

Exist<strong>en</strong> arquitecturas que no ti<strong>en</strong><strong>en</strong> esta restricción, aunque <strong>en</strong> estos casos, los accesos a<br />

palabras alineadas son mucho más rápidos que a palabras <strong>de</strong>salineadas.


Acceso a memoria. Ejemplos<br />

¿Cómo se traduce <strong>en</strong> <strong>en</strong>samblador la expresión <strong>en</strong> C<br />

int a, b, V[40];<br />

a = b + V[8];<br />

Se realiza la asignación <strong>de</strong> registros: a->s0, b->s1,<br />

V->s2.<br />

lw $t0, 32($s2) # t0 se carga con V[8]<br />

add $s0, $s1, $t0 # se realiza la operación<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 13<br />

En este ejemplo, es necesario acce<strong>de</strong>r a un elem<strong>en</strong>to <strong>de</strong> un vector. Obviam<strong>en</strong>te el vector<br />

no cabe <strong>en</strong> los registros <strong><strong>de</strong>l</strong> procesador, por lo que es necesario mant<strong>en</strong>erlo <strong>en</strong> la memoria.<br />

Ahora bi<strong>en</strong>, lo que sí se pue<strong>de</strong> guardar <strong>en</strong> los registros internos es la dirección <strong><strong>de</strong>l</strong> primer elem<strong>en</strong>to<br />

<strong><strong>de</strong>l</strong> vector (lo que <strong>en</strong> C se d<strong>en</strong>ota por el nombre <strong><strong>de</strong>l</strong> vector). En este ejemplo se supone<br />

que se guarda dicha dirección <strong>en</strong> el registro s2. Por tanto, para acce<strong>de</strong>r a la octava palabra <strong><strong>de</strong>l</strong><br />

vector, basta con sumar a la dirección <strong>de</strong> comi<strong>en</strong>zo <strong><strong>de</strong>l</strong> vector el <strong>de</strong>splazami<strong>en</strong>to necesario. La<br />

instrucción <strong>de</strong> carga <strong>de</strong> <strong>MIPS</strong>, d<strong>en</strong>ominada lw (<strong>de</strong> load word), hace precisam<strong>en</strong>te esto: toma<br />

la dirección <strong>de</strong> un registro base y le suma un <strong>de</strong>splazami<strong>en</strong>to,<br />

1 cargando <strong>en</strong>tonces la palabra que<br />

hay <strong>en</strong> la dirección calculada <strong>en</strong> el registro <strong>de</strong>stino. El formato <strong>de</strong> la instrucción es por tanto:<br />

lw Reg_Dest, Despl(Reg_Base)<br />

Hay que t<strong>en</strong>er <strong>en</strong> cu<strong>en</strong>ta que, según se ha discutido antes, las direcciones <strong>de</strong> palabra<br />

aum<strong>en</strong>tan <strong>de</strong> 4 <strong>en</strong> 4, por lo que la octava palabra <strong>de</strong> un vector estará 8 pal · 4Byte/pal =<br />

32Bytes por <strong>en</strong>cima <strong>de</strong> la base <strong><strong>de</strong>l</strong> vector. Por tanto, para cargar V[8] <strong>en</strong> el registgro t0, si la<br />

dirección base <strong><strong>de</strong>l</strong> vector V está almac<strong>en</strong>ada <strong>en</strong> el registro s2, basta con hacer:<br />

lw $t0, 32($s2)<br />

La instrucción complem<strong>en</strong>taria a lw se d<strong>en</strong>omina sw (<strong>de</strong> store word). Su funcionami<strong>en</strong>to<br />

es similar al <strong>de</strong> lw, salvo que <strong>en</strong> lugar <strong>de</strong> traer una palabra <strong>de</strong> la memoria y almac<strong>en</strong>arla <strong>en</strong><br />

un registro; toma la palabra almac<strong>en</strong>ada <strong>en</strong> el registro y la almac<strong>en</strong>a <strong>en</strong> la memoria, concretam<strong>en</strong>te<br />

<strong>en</strong> la dirección Reg_Base + Despl. En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se ilustra su uso<br />

mediante otro ejemplo.<br />

1 El <strong>de</strong>splazami<strong>en</strong>to pue<strong>de</strong> ser positivo o negativo.


Acceso a memoria. Ejemplos<br />

¿Cómo se traduce <strong>en</strong> <strong>en</strong>samblador la expresión <strong>en</strong> C<br />

int b, V[40];<br />

V[12] = b + V[8];<br />

Se realiza la asignación <strong>de</strong> registros: b->s1, V->s2.<br />

lw $t0, 32($s2) # t0 se carga con V[8]<br />

add $t0, $s1, $t0 # se realiza la operación<br />

sw $t0, 48($s2) # t0 se guarda <strong>en</strong> V[12]<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 14<br />

Como se pue<strong>de</strong> apreciar las dos primeras líneas son prácticam<strong>en</strong>te iguales a las <strong><strong>de</strong>l</strong> ejemplo<br />

anterior: tan solo varía el registro <strong>de</strong>stino <strong>de</strong> la suma, que ahora es el registro temporal<br />

t0, <strong>en</strong> don<strong>de</strong> se almac<strong>en</strong>a el resultado <strong>de</strong> la suma antes <strong>de</strong> escribirlo <strong>en</strong> la memoria. De esta<br />

escritura <strong>en</strong> memoria se <strong>en</strong>carga la instrucción sw, la cual ti<strong>en</strong>e el mismo formato que la<br />

instrucción lw:<br />

sw Reg_Orig, Despl(Reg_Base)<br />

En don<strong>de</strong> Reg_Orig es el registro cuyo valor se <strong>de</strong>sea guardar y el resto <strong>de</strong> argum<strong>en</strong>tos<br />

ti<strong>en</strong><strong>en</strong> el mismo significado que antes. Al igual que antes hay que convertir la dirección <strong>de</strong><br />

palabra <strong><strong>de</strong>l</strong> vector a dirección <strong>de</strong> byte (12 pal · 4Byte/pal = 32Bytes) para obt<strong>en</strong>er el <strong>de</strong>splazami<strong>en</strong>to<br />

correcto.<br />

En la mayoría <strong>de</strong> los programas, el acceso a vectores se realiza utilizando un índice<br />

variable. En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se muestra un ejemplo para ilustrar este tipo <strong>de</strong> accesos.


Acceso a memoria. Ejemplos<br />

¿Cómo se traduce <strong>en</strong> <strong>en</strong>samblador la expresión <strong>en</strong> C<br />

int a, b, V[40], i;<br />

a = b + V[i];<br />

Se realiza la asignación <strong>de</strong> registros: a->s0, b->s1,<br />

V->s2, i->s3.<br />

add $t1, $s3, $s3 # t1 = 2*i<br />

add $t1, $t1, $t1 # t1 = 4*i<br />

add $t1, $t1, $s2 # t1 = dir. <strong>de</strong> V[i]<br />

lw $t0, 0($t1) # t0 se carga con V[i]<br />

add $s0, $s1, $t0 # se realiza la operación<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 15<br />

En este ejemplo, al ser el índice variable, no po<strong>de</strong>mos multiplicarlo nosotros a mano<br />

como hemos hecho <strong>en</strong> los ejemplos anteriores cuando el índice era constante. No obstante el<br />

<strong>MIPS</strong> ti<strong>en</strong>e instrucciones que nos permit<strong>en</strong> hacer dicha multiplicación fácilm<strong>en</strong>te. Sin embargo,<br />

como no hemos visto aún la instrucción <strong>de</strong> multiplicación, realizaremos la multiplicación<br />

por 4 mediante dos sumas: En primer lugar calcularemos i + i = 2i y luego 2i + 2i = 4i. De<br />

esto se <strong>en</strong>cargan las dos primeras instrucciones <strong>de</strong> <strong>en</strong>samblador, guardando 4i <strong>en</strong> el registro<br />

t1. Ahora bi<strong>en</strong>, este valor no pue<strong>de</strong> ser usado como <strong>de</strong>splazami<strong>en</strong>to <strong>en</strong> una instrucción <strong>de</strong><br />

carga o almac<strong>en</strong>ami<strong>en</strong>to <strong><strong>de</strong>l</strong> <strong>MIPS</strong>, ya que estas instrucciones sólo admit<strong>en</strong> un <strong>de</strong>splazami<strong>en</strong>to<br />

constante. No obstante la suma <strong><strong>de</strong>l</strong> <strong>de</strong>splazami<strong>en</strong>to con el registro base se pue<strong>de</strong> realizar<br />

mediante otra instrucción add para así calcular la dirección <strong>de</strong> V[i]. De esto se <strong>en</strong>carga la<br />

tercera instrucción <strong><strong>de</strong>l</strong> programa, almac<strong>en</strong>ando dicha dirección <strong>en</strong> el registro t1. En este mom<strong>en</strong>to<br />

ya se pue<strong>de</strong> cargar el valor <strong><strong>de</strong>l</strong> elem<strong>en</strong>to <strong><strong>de</strong>l</strong> vector V[i] mediante la instrucción lw.<br />

Nótese que, como el registro t1 ya conti<strong>en</strong>e la dirección <strong>de</strong> V[i], se ha utilizado un <strong>de</strong>splazami<strong>en</strong>to<br />

<strong>de</strong> 0 <strong>en</strong> la instrucción <strong>de</strong> carga. Una vez cargado el elem<strong>en</strong>to <strong><strong>de</strong>l</strong> vector <strong>en</strong> el registro<br />

t0 ya solo hace falta realizar la operación <strong>de</strong> suma, <strong>de</strong> lo que se <strong>en</strong>carga la última instrucción.<br />

Ejercicio<br />

1. Traduzca a <strong>en</strong>samblador el sigui<strong>en</strong>te código <strong>en</strong> C:<br />

int a, b, V[40], i;<br />

V[i+1] = b + V[i];<br />

V[i-1] = a + V[i];


Codificación <strong>en</strong> l<strong>en</strong>guaje máquina<br />

D<strong>en</strong>tro <strong><strong>de</strong>l</strong> ord<strong>en</strong>ador sólo hay 0’s y 1’s.<br />

Las instrucciones han <strong>de</strong> codificarse <strong>en</strong> binario.<br />

Por ejemplo:<br />

add $t0, $s1, $s2<br />

Se traduce <strong>en</strong> una secu<strong>en</strong>cia <strong>de</strong> 32 1’s y 0’s:<br />

000000 10001 10010 01000 00000 100000<br />

La repres<strong>en</strong>tación binaria está dividida <strong>en</strong> campos<br />

para simplificar su <strong>de</strong>codificación <strong>en</strong> el hardware.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 16<br />

Los programas se escrib<strong>en</strong> <strong>en</strong> l<strong>en</strong>guaje <strong>en</strong>samblador, pero no hay que olvidar que este<br />

l<strong>en</strong>guaje no es más que una repres<strong>en</strong>tación más amigable <strong>de</strong> la única repres<strong>en</strong>tación que<br />

<strong>en</strong>ti<strong>en</strong><strong>de</strong> el procesador: el l<strong>en</strong>guaje máquina. Así, antes <strong>de</strong> po<strong>de</strong>r ejecutar un programa es necesario<br />

traducir cada instrucción <strong>de</strong> l<strong>en</strong>guaje <strong>en</strong>samblador <strong>en</strong> su instrucción correspondi<strong>en</strong>te<br />

<strong>de</strong> l<strong>en</strong>guaje máquina. Este proceso no es muy complicado, según se verá más a<strong><strong>de</strong>l</strong>ante, ya<br />

que para simplificar el hardware esta repres<strong>en</strong>tación binaria se divi<strong>de</strong> <strong>en</strong> campos d<strong>en</strong>tro <strong>de</strong><br />

los cuales se codifica cada una <strong>de</strong> las partes <strong>de</strong> la instrucción: código <strong>de</strong> operación, registros.<br />

. .<br />

En las sigui<strong>en</strong>tes transpar<strong>en</strong>cias se muestra <strong>en</strong> <strong>de</strong>talle cómo es la codificación <strong>de</strong> instrucciones<br />

<strong>en</strong> la arquitectura <strong>MIPS</strong>.


Codificación <strong>en</strong> l<strong>en</strong>guaje máquina<br />

add $t0, $s1, $s2<br />

Operación Destino Fu<strong>en</strong>te 1 Fu<strong>en</strong>te 2<br />

Operación<br />

Fu<strong>en</strong>te 2 no usado<br />

Fu<strong>en</strong>te 1 Destino<br />

0 17 18 8 0 32<br />

000000 10001 10010 01000 00000 100000<br />

Tipo R<br />

ICAI<strong>de</strong>a<br />

6 bits 5 bits 5 bits 5 bits 5 bits 6 bits<br />

op rs rt rd shamtfunct<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 17<br />

InstrucioMichaelG.WPg15ComputerAchiExample<br />

En la transpar<strong>en</strong>cia se muestra la codificación <strong>de</strong> la instrucción:<br />

add $t0, $s1, $s2<br />

Como se dijo <strong>en</strong> el tema anterior, las instrucciones aritméticas <strong><strong>de</strong>l</strong> <strong>MIPS</strong> que operan sólo<br />

con registros se codifican <strong>en</strong> el formato tipo R. Dicho formato comi<strong>en</strong>za con el campo <strong><strong>de</strong>l</strong><br />

código <strong>de</strong> operación (op) <strong>de</strong> 6 bits, que <strong>en</strong> el caso <strong>de</strong> las instrucciones <strong><strong>de</strong>l</strong> tipo R es siempre<br />

0. A continuación vi<strong>en</strong>e un campo <strong>de</strong> 5 bits (rs) <strong>en</strong> don<strong>de</strong> se codifica el número <strong><strong>de</strong>l</strong> primer<br />

registro fu<strong>en</strong>te. En este caso el registro fu<strong>en</strong>te es s1, que según se vio <strong>en</strong> la página 6 es el<br />

registro número 17. En el sigui<strong>en</strong>te campo (rt) se codifica el número <strong><strong>de</strong>l</strong> otro registro fu<strong>en</strong>te,<br />

que <strong>en</strong> este caso es número 18 (s2). En el sigui<strong>en</strong>te campo (rd), también <strong>de</strong> 5 bits, se codifica<br />

el registro <strong>de</strong>stino, 8 <strong>en</strong> este caso (t0, según se pue<strong>de</strong> ver <strong>en</strong> la página 5). El sigui<strong>en</strong>te campo<br />

(shamt) no se usa <strong>en</strong> esta instrucción y por tanto se <strong>de</strong>ja a 0. El último campo (funct) es una<br />

ext<strong>en</strong>sión <strong><strong>de</strong>l</strong> código <strong>de</strong> operación. Este último campo especifica qué instrucción particular<br />

<strong>de</strong> todas las <strong><strong>de</strong>l</strong> tipo R se ha <strong>de</strong> ejecutar. La operación suma se codifica con el número 32.<br />

Nótese que el ord<strong>en</strong> <strong>de</strong> los registros fu<strong>en</strong>te y <strong>de</strong>stino es distinto <strong>en</strong> l<strong>en</strong>guaje <strong>en</strong>samblador<br />

que <strong>en</strong> l<strong>en</strong>guaje máquina.<br />

Las instrucciones <strong>de</strong> carga y almac<strong>en</strong>ami<strong>en</strong>to necesitan especificar dos registros y una<br />

constante. En una primera aproximación al problema podría p<strong>en</strong>sarse <strong>en</strong> utilizar uno <strong>de</strong> los<br />

campos reservados para registros (por ejemplo el rt) para almac<strong>en</strong>ar la constante <strong>en</strong> lugar <strong><strong>de</strong>l</strong><br />

número <strong>de</strong> registro). No obstante con 5 bits sólo se pued<strong>en</strong> repres<strong>en</strong>tar números <strong>en</strong> el rango<br />

0 a 32 o -16 a 15 si se trabaja <strong>en</strong> complem<strong>en</strong>to a 2. Obviam<strong>en</strong>te los vectores y las estructuras<br />

<strong>de</strong> datos usados <strong>en</strong> los programas suel<strong>en</strong> ser mayores <strong>de</strong> 32 bytes, por lo que esta solución no<br />

es muy eficaz. Es preciso por tanto usar otro formato <strong>de</strong> instrucción para las instrucciones <strong>de</strong><br />

carga y almac<strong>en</strong>ami<strong>en</strong>to que permita especificar una constante con un mayor número <strong>de</strong> bits.


Codificación <strong>en</strong> l<strong>en</strong>guaje máquina<br />

lw $t0, 32($s2)<br />

Operación<br />

Destino<br />

Despl.<br />

R. Base<br />

Operación Destino<br />

Fu<strong>en</strong>te 1<br />

35 18 8<br />

32<br />

100011 10010 01000 0000000000010000<br />

Tipo I<br />

ICAI<strong>de</strong>a<br />

6 bits 5 bits 5 bits 16 bits<br />

op rs rt Inmediato<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 18<br />

InstrucioMichaelG.WPg15ComputerAchiExample<br />

En la transpar<strong>en</strong>cia se muestra la codificación <strong>de</strong> la instrucción: lw $t0, 32($s2)<br />

Como esta instrucción necesita una constante para especificar el <strong>de</strong>splazami<strong>en</strong>to, ha <strong>de</strong><br />

codificarse con el formato tipo I. Como se pue<strong>de</strong> apreciar <strong>en</strong> la figura, dicho formato es muy<br />

similar al formato <strong>de</strong> las instrucciones <strong>de</strong> tipo R. La única difer<strong>en</strong>cia consiste <strong>en</strong> que los tres<br />

últimos campos <strong><strong>de</strong>l</strong> tipo R (rd, shamt y funct) se han unido <strong>en</strong> un sólo campo <strong>de</strong> 16 bits<br />

(Inmediato). El hecho <strong>de</strong> que los formatos sean similares simplifica la <strong>de</strong>codificación <strong>de</strong> las<br />

distintas instrucciones.<br />

El significado <strong>de</strong> los dos primeros campos es igual al <strong>de</strong> las instrucciones <strong>de</strong> tipo R: el<br />

primer campo <strong>de</strong> 6 bits especifica el código <strong>de</strong> operación (35 para la instrucción lw) y el<br />

segundo campo especifica el número <strong><strong>de</strong>l</strong> registro base para el acceso a memoria (18 <strong>en</strong> este<br />

ejemplo, que se correspon<strong>de</strong> con el registro s2). El tercer campo especifica un registro, pero<br />

al contrario que <strong>en</strong> las instrucciones <strong>de</strong> tipo R, este registro es el <strong>de</strong>stino <strong>de</strong> la operación.<br />

En este ejemplo, el valor leído <strong>de</strong> la memoria (<strong>en</strong> la dirección (s2) + 32 ) se escribe <strong>en</strong> el<br />

registro número 8 (t0).<br />

Como se pue<strong>de</strong> apreciar, la solución adoptada va contra el primer principio <strong>de</strong> diseño (la<br />

uniformidad simplifica el hardware), ya que <strong>en</strong> lugar <strong>de</strong> t<strong>en</strong>er un formato <strong>de</strong> instrucción fijo<br />

se ti<strong>en</strong><strong>en</strong> formatos distintos <strong>en</strong> función <strong><strong>de</strong>l</strong> tipo <strong>de</strong> instrucción. Esto conduce a otro principio<br />

<strong>de</strong> diseño hardware:<br />

Principio <strong>de</strong> diseño 2: un bu<strong>en</strong> diseño necesita bu<strong>en</strong>as soluciones <strong>de</strong> compromiso.<br />

Obviam<strong>en</strong>te, la solución adoptada <strong>en</strong> este caso complica el hardware al t<strong>en</strong>er que <strong>de</strong>cidir<br />

<strong>en</strong>tre distintos modos <strong>de</strong> <strong>de</strong>codificación <strong>en</strong> función <strong><strong>de</strong>l</strong> tipo <strong>de</strong> instrucción (lo cual, recuer<strong>de</strong>,<br />

vi<strong>en</strong>e marcado por el valor <strong><strong>de</strong>l</strong> código <strong>de</strong> operación). No obstante, con el fin <strong>de</strong> simplificar


la circuitería al máximo, los distintos formatos se han mant<strong>en</strong>ido lo más parecidos posibles.<br />

En este caso, según se ha com<strong>en</strong>tado antes, los tres primeros campos son iguales a los <strong>de</strong> las<br />

instrucciones <strong>de</strong> tipo R.<br />

18-2<br />

Codificación <strong>en</strong> l<strong>en</strong>guaje máquina. Ej.<br />

¿Cómo es el código máquina <strong>de</strong> la expresión <strong>en</strong> C<br />

int a, V[400];<br />

V[300] = V[300] + a;<br />

Si se realiza la asignación <strong>de</strong> registros: a->s0, V->s1.<br />

Inmediato<br />

op rs st rd shamt funct<br />

lw $t0, 1200($s1) 35 17 8 1200<br />

add $t0, $t0, $s0 0 8 16 8 0 32<br />

sw $t0, 1200($s1) 43 17 8 1200<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 19


En la transpar<strong>en</strong>cia se muestra la traducción a código máquina <strong>de</strong> una s<strong>en</strong>t<strong>en</strong>cia s<strong>en</strong>cilla<br />

<strong>en</strong> C:<br />

int a, V[400];<br />

V[300] = V[300] + a;<br />

La primera instrucción conti<strong>en</strong>e un 35 como código <strong>de</strong> operación (lw) seguido <strong>de</strong> un 17<br />

para id<strong>en</strong>tificar el registro base (s1), un 8 para indicar el registro <strong>de</strong>stino (t0) y un 1200 para<br />

seleccionar un <strong>de</strong>splazami<strong>en</strong>to <strong>de</strong> 300 palabras (300 pal · 4Byte/pal = 1200Bytes).<br />

De la misma manera, la instrucción sigui<strong>en</strong>te (add) se codifica con un 0 <strong>en</strong> el campo<br />

<strong>de</strong> código <strong>de</strong> operación y un 32 <strong>en</strong> el último campo (funct). El segundo y tercer campo<br />

id<strong>en</strong>tifican los registros fu<strong>en</strong>te (t0 y s0) y el cuarto campo indica el registro <strong>de</strong>stino (t0). El<br />

p<strong>en</strong>último campo no se usa <strong>en</strong> esta instrucción y por eso se <strong>de</strong>ja a 0.<br />

Por último, nótese que la tercera instrucción es similar a la primera: se guarda el cont<strong>en</strong>ido<br />

<strong><strong>de</strong>l</strong> registro <strong>en</strong> la posición <strong>de</strong> memoria <strong>en</strong> lugar <strong>de</strong> leerlo. Por tanto, lo único que varía<br />

es el código <strong>de</strong> operación (43 <strong>en</strong> lugar <strong>de</strong> 35), si<strong>en</strong>do el resto <strong>de</strong> campos idénticos a los <strong>de</strong> la<br />

primera instrucción.<br />

En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se muestra la codificación <strong>en</strong> binario, que es la que “ve”<br />

realm<strong>en</strong>te el procesador.<br />

Codificación <strong>en</strong> l<strong>en</strong>guaje máquina. Ej.<br />

La codificación <strong>en</strong> binario es:<br />

Inmediato<br />

op rs st rd shamt funct<br />

100011 10001 01000 0000 0100 1011 0000<br />

000000 01000 10000 01000 00000 100000<br />

101011 10001 01000 0000 0100 1011 0000<br />

La única difer<strong>en</strong>cia <strong>en</strong>tre la 1 a y la 3 a instrucción es el<br />

tercer bit.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 20


En la transpar<strong>en</strong>cia se muestra la codificación <strong>de</strong> las instrucciones <strong>en</strong> binario, que es el<br />

formato <strong>en</strong> el que las “ve” el procesador. No obstante esta notación es muy oscura para los<br />

programadores, por lo que no se usa <strong>en</strong> la práctica. Se ha usado aquí simplem<strong>en</strong>te con fines<br />

ilustrativos.<br />

Nótese que para simplificar la <strong>de</strong>codificación, instrucciones similares se codifican <strong>de</strong><br />

forma similar. En este caso la difer<strong>en</strong>cia <strong>en</strong>tre la 1 a y la 3 a instrucción consiste solam<strong>en</strong>te <strong>en</strong><br />

el tercer bit empezando por la izquierda (bit 29 <strong>de</strong> la palabra).<br />

Por último, es necesario resaltar que las instrucciones <strong>de</strong> un programa no son más que<br />

una secu<strong>en</strong>cia <strong>de</strong> números. Así, el código anterior no son más que tres números binarios <strong>de</strong><br />

32 bits. En concreto:<br />

240386168<br />

17842208<br />

2921858224<br />

Por tanto las instrucciones se pued<strong>en</strong> almac<strong>en</strong>ar <strong>en</strong> la memoria al igual que los datos.<br />

Esta es una <strong>de</strong> las i<strong>de</strong>as fundam<strong>en</strong>tales <strong>de</strong> la informática y es precisam<strong>en</strong>te lo que hace que<br />

los ord<strong>en</strong>adores sean unas máquinas trem<strong>en</strong>dam<strong>en</strong>te flexibles: basta con cambiar el programa<br />

para que un ord<strong>en</strong>ador pase a realizar una tarea totalm<strong>en</strong>te distinta.<br />

Toma <strong>de</strong> <strong>de</strong>cisiones<br />

La toma <strong>de</strong> <strong>de</strong>cisiones es lo que distingue a un<br />

ord<strong>en</strong>ador <strong>de</strong> una calculadora.<br />

Permite ejecutar distintas instrucciones <strong>en</strong> función <strong>de</strong><br />

datos <strong>de</strong> <strong>en</strong>trada o resultados <strong>de</strong> cálculos.<br />

En <strong>MIPS</strong> se incluy<strong>en</strong> 2 instrucciones para toma <strong>de</strong><br />

<strong>de</strong>cisiones:<br />

• beq reg1, reg2, L1<br />

• bne reg1, reg2, L1<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 21


La posibilidad <strong>de</strong> tomar <strong>de</strong>cisiones <strong>en</strong> función <strong>de</strong> los datos <strong>de</strong> <strong>en</strong>trada o <strong><strong>de</strong>l</strong> resultado <strong>de</strong><br />

un cálculo es lo que distingue a un ord<strong>en</strong>ador <strong>de</strong> una simple calculadora. Por ello todos los<br />

procesadores incluy<strong>en</strong> instrucciones que permitan ejecutar una serie <strong>de</strong> instrucciones u otras<br />

<strong>en</strong> función <strong>de</strong> un resultado lógico. Esta toma <strong>de</strong> <strong>de</strong>cisiones se repres<strong>en</strong>ta <strong>en</strong> los l<strong>en</strong>guajes <strong>de</strong><br />

programación mediante la s<strong>en</strong>t<strong>en</strong>cia if.<br />

La arquitectura <strong>MIPS</strong> incluye dos instrucciones que permit<strong>en</strong> tomar <strong>de</strong>cisiones <strong>en</strong> función<br />

<strong>de</strong> los valores almac<strong>en</strong>ados <strong>en</strong> dos <strong>de</strong> sus registros:<br />

• beq reg1, reg2, L1. Esta instrucción compara los cont<strong>en</strong>idos <strong>de</strong> los registros<br />

reg1 y reg2. Si son iguales, el programa salta a la instrucción etiquetada con L1. Si<br />

son distintos, el programa continúa <strong>en</strong> la instrucción sigui<strong>en</strong>te (a beq). El nemónico<br />

beq vi<strong>en</strong>e <strong>de</strong> branch if equal.<br />

• bne reg1, reg2, L1. Al igual que la instrucción anterior, esta instrucción compara<br />

los cont<strong>en</strong>idos <strong>de</strong> los registros reg1 y reg2. Si son distintos, el programa salta a la<br />

instrucción etiquetada con L1. Si son iguales, el programa continúa <strong>en</strong> la instrucción<br />

sigui<strong>en</strong>te. El nemónico bne vi<strong>en</strong>e <strong>de</strong> branch if not equal.<br />

Debido a su modo <strong>de</strong> funcionami<strong>en</strong>to, este tipo <strong>de</strong> instrucciones se conoc<strong>en</strong> como saltos<br />

condicionales.<br />

El equival<strong>en</strong>te <strong>en</strong> C <strong>de</strong> ambas instrucciones es, respectivam<strong>en</strong>te:<br />

• if(i==j) goto L1;<br />

• if(i!=j) goto L1;<br />

En don<strong>de</strong> se ha supuesto que las variables i y j están almac<strong>en</strong>adas <strong>en</strong> los registros Reg1<br />

y Reg2.<br />

Toma <strong>de</strong> <strong>de</strong>cisiones. Ejemplo<br />

¿Cómo se traduce <strong>en</strong> <strong>en</strong>samblador la expresión <strong>en</strong> C<br />

int a, b, c, i, j;<br />

if(i == j) goto L1;<br />

b = b + c;<br />

L1: a = b - c;<br />

Si las variables a-j se asignan a los registros s0-s4.<br />

beq $s3, $s4, L1 # Si i==j ir a L1<br />

add $s1, $s1, $s2 # se ejecuta si i!=j<br />

L1: sub $s0, $s1, $s2 # se ejecuta siempre<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 22


En el fragm<strong>en</strong>to <strong>de</strong> código C mostrado, se realiza un salto a la instrucción etiquetada<br />

con L1 sólo si las variables i y j son iguales. Por tanto, la instrucción b = b + c sólo se<br />

ejecutará si i!=j y la instrucción a = b - c se ejecutará siempre. Nótese que este ejemplo<br />

es muy “artificial”, ya que sólo persigue ilustrar las instrucciones <strong>de</strong> salto condicional <strong>de</strong> la<br />

arquitectura <strong>MIPS</strong>. De hecho, la mayoría <strong>de</strong> los programadores evita el uso <strong>de</strong> s<strong>en</strong>t<strong>en</strong>cias<br />

goto <strong>en</strong> sus programas. En el sigui<strong>en</strong>te ejemplo se mostrará cómo codificar la s<strong>en</strong>t<strong>en</strong>cia<br />

if-th<strong>en</strong>-else, que es la que se usa normalm<strong>en</strong>te.<br />

La traducción a <strong>en</strong>samblador es directa. La s<strong>en</strong>t<strong>en</strong>cia if se traduce por:<br />

beq $s3, $s4, L1 # Si i==j ir a L1<br />

En don<strong>de</strong> la etiqueta L1, al igual que <strong>en</strong> C, id<strong>en</strong>tifica la instrucción a la que es necesario<br />

saltar si la condición es cierta. La sigui<strong>en</strong>te s<strong>en</strong>t<strong>en</strong>cia también equivale a una sola instrucción:<br />

add $s1, $s1, $s2 # se ejecuta si i!=j<br />

La última s<strong>en</strong>t<strong>en</strong>cia <strong>en</strong> C también se traduce por una sola instrucción <strong>en</strong> <strong>en</strong>samblador,<br />

sólo que ahora es necesario incluir la etiqueta <strong>de</strong> forma que la instrucción <strong>de</strong> salto condicional<br />

pueda saltar a ella cuando la comparación sea cierta. Para ello basta con añadir el nombre <strong>de</strong><br />

la etiqueta terminado con el carácter ’:’ <strong><strong>de</strong>l</strong>ante <strong>de</strong> la instrucción:<br />

L1: sub $s0, $s1, $s2 # se ejecuta siempre<br />

De este modo el <strong>en</strong>samblador hace correspon<strong>de</strong>r la etiqueta L1 con la dirección <strong>de</strong> la<br />

instrucción sub $s0, $s1, $s2. Cuando éste traduzca la primera instrucción a l<strong>en</strong>guaje<br />

máquina, la etiqueta L1 será sustituida por la dirección <strong>de</strong> la tercera instrucción. Por tanto el<br />

<strong>en</strong>samblador está liberando al programador <strong>de</strong> otra tarea muy tediosa y prop<strong>en</strong>sa a errores: el<br />

cálculo <strong>de</strong> las direcciones <strong>de</strong> salto.<br />

22-2


Toma <strong>de</strong> <strong>de</strong>cisiones. Ejemplo<br />

ICAI<strong>de</strong>a<br />

int a, b, c, i, j;<br />

if(i == j){<br />

a = b + c;<br />

}else{<br />

a = b - c;<br />

}<br />

Se traduce <strong>en</strong> (a-j se asignan a los registros s0-s4):<br />

bne $s3, $s4, SiNo # Si i!=j ir a SiNo<br />

add $s0, $s1, $s2 # se evita si i!=j<br />

j Fin<br />

# Salta a Fin<br />

SiNo: sub $s0, $s1, $s2 # se ejecuta si i!=j<br />

Fin:<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 23<br />

En la transpar<strong>en</strong>cia se muestra cómo se traduce una s<strong>en</strong>t<strong>en</strong>cia if-else a <strong>en</strong>samblador<br />

<strong>MIPS</strong>. En primer lugar, al igual que <strong>en</strong> el ejemplo anterior, la s<strong>en</strong>t<strong>en</strong>cia if se traduce por una<br />

instrucción <strong>de</strong> salto condicional. Sin embargo, ahora se comprueba la condición contraria<br />

para saltar al bloque else si la condición <strong><strong>de</strong>l</strong> if es falsa:<br />

bne $s3, $s4, SiNo # Si i!=j ir a SiNo<br />

La sigui<strong>en</strong>te s<strong>en</strong>t<strong>en</strong>cia <strong>de</strong> C, al t<strong>en</strong>er todos sus operandos situados <strong>en</strong> registros se traduce<br />

por una sola instrucción <strong>de</strong> <strong>en</strong>samblador:<br />

add $s0, $s1, $s2 # se evita si i!=j<br />

Una vez ejecutada esta instrucción, es necesario que el programa continúe <strong>de</strong>spués <strong>de</strong> la<br />

s<strong>en</strong>t<strong>en</strong>cia if. Para ello es necesario introducir una nueva instrucción <strong><strong>de</strong>l</strong> <strong>en</strong>samblador <strong>MIPS</strong>:<br />

el salto incondicional. Esta instrucción se id<strong>en</strong>tifica mediante el nemónico j (<strong>de</strong> jump). Su<br />

formato es simplem<strong>en</strong>te j Etiqueta. En este caso:<br />

j Fin # Salta a Fin<br />

Esta instrucción hace que el procesador salte siempre a la instrucción marcada por la<br />

etiqueta Fin. A continuación se sitúa el resultado <strong>de</strong> traducir la s<strong>en</strong>t<strong>en</strong>cia <strong><strong>de</strong>l</strong> else <strong><strong>de</strong>l</strong> programa<br />

<strong>en</strong> C. Al igual que antes, esta s<strong>en</strong>t<strong>en</strong>cia se traduce a una sola instrucción aritmética. No<br />

obstante, es necesario prece<strong>de</strong>r dicha instrucción por la etiqueta SiNo, ya que esta instrucción<br />

es el <strong>de</strong>stino <strong><strong>de</strong>l</strong> salto <strong>de</strong> la comaración:<br />

SiNo: sub $s0, $s1, $s2 # se ejecuta si i!=j<br />

Por último, es necesario incluir la etiqueta Fin, que es el <strong>de</strong>stino <strong><strong>de</strong>l</strong> salto incondicional


al final <strong>de</strong> la s<strong>en</strong>t<strong>en</strong>cia if. Dicha etiqueta repres<strong>en</strong>tará la dirección <strong>de</strong> la instrucción sigui<strong>en</strong>te,<br />

que no se ha mostrado <strong>en</strong> la transpar<strong>en</strong>cia para simplificar. Por ejemplo, si la sigui<strong>en</strong>te<br />

instrucción <strong><strong>de</strong>l</strong> programa <strong>en</strong> <strong>en</strong>samblador fuese add $t0, $t0, $t1, <strong>en</strong>tonces el final <strong><strong>de</strong>l</strong><br />

programa anterior sería:<br />

Fin:<br />

add $t0, $t0, $t1<br />

Nótese que no es necesario que la etiqueta esté <strong>en</strong> la misma línea que la instrucción.<br />

Únicam<strong>en</strong>te ha <strong>de</strong> escribirse antes <strong>de</strong> ella.<br />

Ejercicios<br />

1. Traduzca a <strong>en</strong>samblador el ejemplo mostrado <strong>en</strong> la transpar<strong>en</strong>cia usando la instrucción<br />

beq para realizar la comparación <strong>en</strong>tre i y j.<br />

2. Traduzca a <strong>en</strong>samblador el sigui<strong>en</strong>te código <strong>en</strong> C:<br />

int a, b, c, i, j;<br />

if(i == j){<br />

a = b + c;<br />

}


Toma <strong>de</strong> <strong>de</strong>cisiones. Bucles<br />

int a, V[100], i, j, k;<br />

Bucle: a = a + V[i];<br />

i = i + j;<br />

if( i != k) goto Bucle;<br />

Se traduce <strong>en</strong> (a-k se asignan a los registros s0-s4):<br />

Bucle: add $t1, $s2, $s2 # t1 = 2i<br />

add $t1, $t1, $t1 # t1 = 4i<br />

add $t1, $t1, $s1 # t1 = dir. <strong>de</strong> V[i]<br />

lw $t0, 0($t1) # t0 = V[i]<br />

add $s0, $s0, $t0 # a = a + V[i]<br />

add $s2, $s2, $s3 # i = i + j<br />

bne $s2, $s4, Bucle # si i!=k salta<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 24<br />

Al igual que se hizo con el ejemplo <strong><strong>de</strong>l</strong> if, esta forma <strong>de</strong> escribir un bucle <strong>en</strong> C no<br />

es la más común. Es más, no es nada recom<strong>en</strong>dable su uso. Sin embargo, su traducción<br />

a <strong>en</strong>samblador es directa y por ello se ha usado <strong>en</strong> este primer ejemplo. En la sigui<strong>en</strong>te<br />

transpar<strong>en</strong>cia se mostrará cómo se traduce un bucle while a <strong>en</strong>samblador <strong>MIPS</strong>.<br />

El programa <strong>en</strong> C repite las dos primeras instrucciones mi<strong>en</strong>tras i!=k. La primera instrucción<br />

conti<strong>en</strong>e un acceso a un vector. Por lo tanto es necesario multiplicar por 4 el índice<br />

i (s2), <strong>de</strong> lo que se <strong>en</strong>cargan las dos primeras instrucciones. La tercera instrucción calcula la<br />

dirección <strong><strong>de</strong>l</strong> elem<strong>en</strong>to <strong><strong>de</strong>l</strong> vector y por último la cuarta lo carga <strong>en</strong> el registro t0. La sigui<strong>en</strong>te<br />

instrucción calcula a = a + V[i] y la sexta i = i + j. La última instrucción saltará al<br />

principio <strong><strong>de</strong>l</strong> bucle si se cumple la condición i!=k. En caso contrario el programa continuará<br />

<strong>en</strong> la instrucción que sigue a bne, terminándose así el bucle.<br />

Ejercicio<br />

Modifique el programa anterior para evitar el cálculo <strong>de</strong> 4*i <strong>en</strong> cada iteración <strong><strong>de</strong>l</strong> bucle.<br />

¿Cuantas instrucciones se repit<strong>en</strong> ahora <strong>en</strong> cada iteración Suponi<strong>en</strong>do que todas las instrucciones<br />

tardan lo mismo <strong>en</strong> ejecutarse, ¿Cual será la mejora <strong>en</strong> el tiempo <strong>de</strong> ejecución <strong>de</strong> un<br />

programa que repita este bucle 10 veces


Toma <strong>de</strong> <strong>de</strong>cisiones. Bucles<br />

int a, V[100], i, j, k;<br />

while(V[i] == k){<br />

i = i + j;<br />

}<br />

Se traduce <strong>en</strong> (a-k se asignan a los registros s0-s4):<br />

Bucle: add $t1, $s2, $s2 # t1 = 2i<br />

add $t1, $t1, $t1 # t1 = 4i<br />

add $t1, $t1, $s1 # t1 = dir. <strong>de</strong> V[i]<br />

lw $t0, 0($t1) # t0 = V[i]<br />

bne $t0, $s4, Fin # si i!=k salta<br />

add $s2, $s2, $s3 # i = i + j<br />

j Bucle<br />

Fin:<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 25<br />

En esta transpar<strong>en</strong>cia se muestra la traducción a <strong>en</strong>samblador <strong>de</strong> un bucle while <strong>en</strong> C.<br />

Como se pue<strong>de</strong> apreciar, aunque este bucle es más fácil <strong>de</strong> usar que el anterior, su traducción<br />

a <strong>en</strong>samblador es un poco más compleja. Afortunadam<strong>en</strong>te este trabajo extra <strong>de</strong> traducción<br />

lo realiza normalm<strong>en</strong>te el compilador.<br />

Las 4 primeras instrucciones son las mismas que <strong>en</strong> el ejemplo anterior, ya que lo primero<br />

que hay que hacer es cargar el valor V[i] <strong>de</strong>s<strong>de</strong> la memoria al registro t0. Una vez cargado<br />

dicho valor, se pue<strong>de</strong> evaluar la condición <strong><strong>de</strong>l</strong> bucle while. Esto se realiza <strong>en</strong> la 5 a instrucción.<br />

En ella se compara el valor <strong>de</strong> V[i] (t0) con el valor <strong>de</strong> k (s4). Si son distintos se salta a la<br />

etiqueta Fin, terminándose así el bucle. Si son iguales, se continuará ejecutando la sigui<strong>en</strong>te<br />

instrucción para realizar la suma i = i+j, es <strong>de</strong>cir, se ejecuta el “cuerpo” <strong><strong>de</strong>l</strong> bucle. Una vez<br />

realizada la suma se salta al principio <strong><strong>de</strong>l</strong> bucle mediante un salto incondicional. Nótese que<br />

<strong>en</strong> la instrucción <strong>de</strong> comparación se ha cambiado la condición que aparece <strong>en</strong> el código C<br />

para conseguir un código más compacto.<br />

Ejercicio<br />

Traduzca el bucle while anterior a <strong>en</strong>samblador <strong>MIPS</strong> pero utilizando la instrucción beq<br />

<strong>en</strong> lugar <strong>de</strong> la instrucción bne.


Toma <strong>de</strong> <strong>de</strong>cisiones. M<strong>en</strong>or que<br />

• Las comparaciones más habituales <strong>en</strong> los<br />

programas son la igualdad y la <strong>de</strong>sigualdad.<br />

• Es necesario también saber si una variable es<br />

m<strong>en</strong>or que otra. Para ello <strong>MIPS</strong> <strong>de</strong>fine la<br />

instrucción slt (set on less than).<br />

• Por ejemplo: la instrucción slt $t0, $s3, $s4<br />

Pone a 1 t0 si s3 es m<strong>en</strong>or que s4. Si no t0 se<br />

pone a 0.<br />

• Combinando slt, bne, beq y el registro zero se<br />

pued<strong>en</strong> realizar todas las comparaciones.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 26<br />

Aunque las comparaciones más habituales <strong>en</strong> los programas son la igualdad y la <strong>de</strong>sigualdad,<br />

<strong>en</strong> muchas ocasiones es necesario saber si el valor <strong>de</strong> una variable es m<strong>en</strong>or que otra.<br />

Por ejemplo <strong>en</strong> un bucle for que recorre un vector es muy frecu<strong>en</strong>te comparar si el índice<br />

es m<strong>en</strong>or que la dim<strong>en</strong>sión <strong><strong>de</strong>l</strong> vector. Para realizar este tipo <strong>de</strong> comparaciones, la arquitectura<br />

<strong>MIPS</strong> <strong>de</strong>fine la instrucción slt (<strong>de</strong> set on less than). Dicha instrucción consta <strong>de</strong> tres<br />

argum<strong>en</strong>tos, un registro <strong>de</strong>stino y dos registros fu<strong>en</strong>te:<br />

slt <strong>de</strong>stino, fu<strong>en</strong>te1, fu<strong>en</strong>te2<br />

Su funcionami<strong>en</strong>to consiste <strong>en</strong> comparar si el cont<strong>en</strong>ido <strong><strong>de</strong>l</strong> registro fu<strong>en</strong>te1 es m<strong>en</strong>or<br />

que el <strong><strong>de</strong>l</strong> registro fu<strong>en</strong>te2. En caso afirmativo escribe un 1 <strong>en</strong> el registro <strong>de</strong>stino y <strong>en</strong> caso<br />

negativo escribe un 0.<br />

En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se muestra un ejemplo <strong><strong>de</strong>l</strong> uso <strong>de</strong> esta instrucción para<br />

traducir una s<strong>en</strong>t<strong>en</strong>cia if a <strong>en</strong>samblador.<br />

Ejercicio<br />

Los compiladores <strong><strong>de</strong>l</strong> <strong>MIPS</strong> utilizan las instrucciones slt, bne, beq y el valor cero (almac<strong>en</strong>ado<br />

<strong>en</strong> el “registro” zero) para realizar todas las comparaciones posibles (==, !=, , =). Escriba las secu<strong>en</strong>cias <strong>de</strong> instrucciones <strong>MIPS</strong> que permit<strong>en</strong> evaluar dichas condiciones<br />

<strong>en</strong>tre los registros s0 y s1 y saltar a la etiqueta Fin si el resultado <strong>de</strong> la comparación<br />

es cierto. Por ejemplo, para evaluar la condición s0 > s1 se escribiría:<br />

slt $t0, $s1, Ss0<br />

bne $t0, $zero, Fin


Toma <strong>de</strong> <strong>de</strong>cisiones. Ejemplo<br />

int a, b, c, i, j;<br />

if(i >= j){<br />

a = b + c;<br />

}<br />

Se traduce <strong>en</strong> (a-j se asignan a los registros s0-s4):<br />

slt $t0, $s3, $s4 # evalúa i < j<br />

bne $t0, $zero, Fin # si i= j, se ha evaluado la contraria (i < j) para saltarse el<br />

“cuerpo” <strong><strong>de</strong>l</strong> if si dicha condición contraria es cierta.<br />

En este caso la evaluación <strong>de</strong> la condición y el salto se realizan <strong>en</strong> dos pasos. En primer<br />

lugar con la instrucción:<br />

slt $t0, $s3, $s4 # evalúa i < j<br />

Se evalúa la condición i < j y se actualiza el valor <strong><strong>de</strong>l</strong> registro t0 con el resultado <strong>de</strong> la<br />

comparación. A continuación, mediante una instrucción <strong>de</strong> salto condicional se salta al final<br />

<strong><strong>de</strong>l</strong> if si el resultado <strong>de</strong> la comparación anterior ha sido cierto:<br />

bne $t0, $zero, Fin # si i


Llamadas a funciones<br />

Las funciones permit<strong>en</strong> programas estructurados,<br />

reutilizar código, etc.<br />

Dos aspectos importantes:<br />

• Ti<strong>en</strong><strong>en</strong> un interfaz bi<strong>en</strong> <strong>de</strong>finido: Parámetros <strong>de</strong><br />

<strong>en</strong>trada y resultados <strong>de</strong> salida.<br />

• Realizan su trabajo sin interferir con la función<br />

que las llama.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 28<br />

En cualquier programa, salvo que éste sea extremadam<strong>en</strong>te simple, es necesario usar<br />

funciones. El uso <strong>de</strong> funciones pres<strong>en</strong>ta numerosas v<strong>en</strong>tajas, <strong>en</strong>tre las que <strong>de</strong>stacan la mejora<br />

<strong>de</strong> la legibilidad <strong><strong>de</strong>l</strong> programa, la posibilidad <strong>de</strong> reutilizar código, el facilitar la programación<br />

al permitir dividir un problema complejo <strong>en</strong> varios “subproblemas” más fáciles <strong>de</strong> abordar,<br />

etc.<br />

Aunque ya <strong>de</strong>be <strong>de</strong> estar familiarizado con el uso <strong>de</strong> funciones <strong>en</strong> l<strong>en</strong>guajes <strong>de</strong> alto nivel,<br />

convi<strong>en</strong>e recalcar dos aspectos <strong>de</strong> su uso:<br />

• Constan <strong>de</strong> un interfaz bi<strong>en</strong> <strong>de</strong>finido con el resto <strong><strong>de</strong>l</strong> programa. Recib<strong>en</strong> una serie <strong>de</strong><br />

argum<strong>en</strong>tos con los que realiza su tarea y <strong>de</strong>vuelv<strong>en</strong> el resultado <strong>de</strong> ésta a “qui<strong>en</strong>” la<br />

ha llamado.<br />

• Son capaces <strong>de</strong> realizar su tarea sin interferir con el resto <strong><strong>de</strong>l</strong> programa. Esto se consigue<br />

mediante un espacio <strong>de</strong> trabajo propio aislado <strong><strong>de</strong>l</strong> resto <strong><strong>de</strong>l</strong> programa. Así, las<br />

variables que utiliza son locales a la función y no son accesibles <strong>de</strong>s<strong>de</strong> fuera <strong>de</strong> ella.<br />

De la misma forma, la función no pue<strong>de</strong> acce<strong>de</strong>r a las variables locales <strong>de</strong> las <strong>de</strong>más<br />

funciones.


Llamadas a funciones<br />

Para po<strong>de</strong>r ejecutar una función es necesario:<br />

1. Situar los parámetros don<strong>de</strong> la función llamada<br />

pueda leerlos. a0-a3, pila<br />

2. Transferir el control a la función llamada.<br />

3. Reservar espacio para las variables locales.<br />

t0-t9, pila.<br />

4. Realizar la tarea necesaria.<br />

5. Situar el resultado don<strong>de</strong> la función llamante<br />

pueda leerlos. v0-v1, pila<br />

6. Devolver el control a la función llamante.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 29<br />

En la transpar<strong>en</strong>cia se muestran los distintos pasos que es necesario realizar <strong>en</strong> la llamada<br />

a una función.<br />

Tanto el <strong>en</strong>vío <strong>de</strong> argum<strong>en</strong>tos (paso 1) como la reserva <strong>de</strong> espacio para las variables<br />

locales (paso 3) y la recepción <strong>de</strong> los resultados (paso 5) son tarea <strong><strong>de</strong>l</strong> programador (o <strong><strong>de</strong>l</strong><br />

compilador si se programa <strong>en</strong> un l<strong>en</strong>guaje <strong>de</strong> alto nivel). Ahora bi<strong>en</strong>, todo ello se realiza<br />

sigui<strong>en</strong>do una conv<strong>en</strong>ción software para que todas las funciones puedan interactuar sin problemas,<br />

in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>tem<strong>en</strong>te <strong>de</strong> su autor y <strong><strong>de</strong>l</strong> l<strong>en</strong>guaje <strong>en</strong> que hayan sido escritas. En el caso<br />

<strong><strong>de</strong>l</strong> <strong>MIPS</strong>, con el objetivo <strong>de</strong> conseguir mejores prestaciones, se reservan 4 registros (a0-a3)<br />

para <strong>en</strong>viar argum<strong>en</strong>tos a la función y 2 registros (v0-v1) para que la función <strong>de</strong>vuelva su<br />

resultado. Si se necesita <strong>en</strong>viar a la función un número mayor <strong>de</strong> argum<strong>en</strong>tos o datos que no<br />

puedan ser almac<strong>en</strong>ados <strong>en</strong> registros, <strong>en</strong>tonces es necesario recurrir a la pila. De la misma<br />

forma, si la función ha <strong>de</strong> <strong>de</strong>volver algún dato que no quepa <strong>en</strong> los registros (v0-v1), como<br />

por ejemplo una estructura <strong>de</strong> datos, será necesario recurrir a la pila. Las variables locales se<br />

pued<strong>en</strong> almac<strong>en</strong>ar <strong>en</strong> los registros reservados para valores temporales (t0-t9) o <strong>en</strong> la pila. En<br />

caso necesario se pued<strong>en</strong> usar también los registros (s0-s7), aunque antes <strong>de</strong> escribir nada<br />

<strong>en</strong> ellos será necesario guardar su valor <strong>en</strong> la pila y restaurarlos justo antes <strong>de</strong> <strong>de</strong>volver el<br />

control a la función llamante, pues dicha función supone que la función llamada <strong>de</strong>jará estos<br />

registros intactos. En otras arquitecturas (p. ej. IA-32) <strong>de</strong>bido al escaso número <strong>de</strong> registros<br />

disponible (8) no se reservan registros para el paso <strong>de</strong> argum<strong>en</strong>tos ni para valores temporales,<br />

si<strong>en</strong>do <strong>en</strong>tonces necesario un uso int<strong>en</strong>sivo <strong>de</strong> la pila.<br />

El último aspecto <strong>de</strong> la llamada a una función (paso 6) es la continuación <strong>de</strong> la ejecución<br />

<strong>de</strong> la función llamante justo <strong>en</strong> la instrucción sigui<strong>en</strong>te a la usada para realizar la llamada a la<br />

función (paso 2). Para ello es necesario guardar la dirección <strong>de</strong> dicha instrucción sigui<strong>en</strong>te <strong>en</strong><br />

algún sitio, lo cual necesita que el procesador incluya hardware específico para dicha tarea.


En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se discute la solución adoptada por los arquitectos <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.<br />

29-2<br />

Llamadas a funciones. Instrucción jal<br />

• Al transferir el control a la función es necesario<br />

guardar la dirección <strong>de</strong> retorno.<br />

• En el <strong>MIPS</strong> esta tarea la realiza la instrucción jal<br />

(jump and link)<br />

• Formato: jal Dir_<strong>de</strong>_la_función<br />

• Funcionami<strong>en</strong>to:<br />

• Guarda la dirección <strong>de</strong> retorno (PC+4) <strong>en</strong> el<br />

registro ra.<br />

• Salta a la dirección Dir_<strong>de</strong>_la_función.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 30


La instrucción jal (<strong><strong>de</strong>l</strong> inglés jump and link, saltar y <strong>en</strong>lazar) permite saltar a la dirección<br />

<strong>de</strong> su argum<strong>en</strong>to (jump) y a la vez almac<strong>en</strong>ar la dirección <strong>de</strong> la instrucción <strong>de</strong> retorno<br />

(link), que será la instrucción que esté situada a continuación <strong>de</strong> jal. Dicha dirección será<br />

obviam<strong>en</strong>te PC+4. El lugar elegido por los arquitectos <strong><strong>de</strong>l</strong> <strong>MIPS</strong> para almac<strong>en</strong>ar la dirección<br />

<strong>de</strong> retorno es un registro reservado para este fin, d<strong>en</strong>ominado ra (<strong><strong>de</strong>l</strong> inglés return address,<br />

dirección <strong>de</strong> retorno). Esto permite que la ejecución <strong>de</strong> la instrucción se realice <strong>en</strong> un solo<br />

ciclo <strong>de</strong> reloj. Las arquitecturas CISC guardan la dirección <strong>de</strong> retorno <strong>en</strong> la pila, aunque<br />

esto conlleva un tiempo <strong>de</strong> ejecución mayor, pues hace falta hacer un acceso adicional a la<br />

memoria para guardar la dirección <strong>de</strong> retorno.<br />

Por ejemplo, si se <strong>de</strong>sea saltar a la función llamada fun bastará con escribir:<br />

jal fun<br />

A<strong>de</strong>más <strong>de</strong> esto, es necesario que la primera instrucción <strong>de</strong> la función t<strong>en</strong>ga como etiqueta<br />

fun:<br />

fun: add $t0, $a0, $a1<br />

...<br />

Llamadas a funciones. Instrucción jr<br />

• Para volver <strong>de</strong> una función es necesario saltar a<br />

la dirección almac<strong>en</strong>ada <strong>en</strong> ra<br />

• En el <strong>MIPS</strong> esta tarea se realiza con la<br />

instrucción jr (jump register).<br />

• Formato: jr registro<br />

• Funcionami<strong>en</strong>to: Salta a la dirección almac<strong>en</strong>ada<br />

<strong>en</strong> el registro.<br />

Por tanto, el retorno <strong>de</strong> la función se realiza con:<br />

jr $ra<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 31


Por último, una vez finalizada su tarea, la función ha <strong>de</strong> colocar el resultado <strong>en</strong> los<br />

registros v0-v1 o la pila y <strong>de</strong>volver el control a la función que la ha llamado. Como la llamada<br />

a la función mediante la instrucción jal guarda la dirección <strong>de</strong> la instrucción que le sigue<br />

<strong>en</strong> el registro ra, basta con saltar a la dirección almac<strong>en</strong>ada <strong>en</strong> dicho registro. Para ello,<br />

el <strong>MIPS</strong> dispone <strong>de</strong> una instrucción que permite saltar incondicionalm<strong>en</strong>te a la dirección<br />

almac<strong>en</strong>ada <strong>en</strong> un registro, llamada jr (<strong><strong>de</strong>l</strong> ingles jump register, saltar registro). Por tanto, la<br />

última instrucción <strong>de</strong> la función será precisam<strong>en</strong>te:<br />

jr $ra<br />

Resumi<strong>en</strong>do, la función llamante coloca los argum<strong>en</strong>tos <strong>en</strong> los registros a0-a3 y mediante<br />

la instrucción “jal fun” llama a la función fun. Dicha función realiza su tarea y<br />

<strong>de</strong>posita sus resultados <strong>en</strong> los registros v0-v1 para a continuación <strong>de</strong>volver el control a la<br />

función llamante mediante la instrucción jr $ra. En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se muestra<br />

un ejemplo para aclarar el proceso.<br />

Llamadas a funciones. Ejemplo<br />

int funHoja(int g, int h, int i, int j)<br />

{<br />

int f;<br />

f = (g + h) - (i + j);<br />

return f;<br />

}<br />

Se traduce <strong>en</strong> (g-j se pasan <strong>en</strong> los registros a0-a3):<br />

funHoja: add $t0, $a0, $a1 # t0 = g + h<br />

add $t1, $a2, $a3 # t1 = i + j<br />

sub $t0, $t0, $t1 # t0 = (g+h) - (i+j)<br />

add $v0, $t0, $zero # v0 = t0<br />

jr $ra<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 32


En la transpar<strong>en</strong>cia se muestra un ejemplo <strong>de</strong> traducción a <strong>en</strong>samblador <strong>de</strong> una función<br />

muy simple escrita <strong>en</strong> C. Como se pue<strong>de</strong> apreciar <strong>en</strong> primer lugar, dicha función no llama<br />

a ninguna otra. A este tipo <strong>de</strong> funciones se les d<strong>en</strong>omina funciones hoja. A<strong>de</strong>más, dicha<br />

función sólo necesita 4 argum<strong>en</strong>tos, por lo que no es necesario recurrir a la pila. De la misma<br />

forma, como la función <strong>de</strong>vuelve un valor <strong>en</strong>tero, basta con un sólo registro para ello (v0).<br />

Como se pue<strong>de</strong> observar, la función sólo necesita almac<strong>en</strong>ar dos valores <strong>en</strong> variables<br />

locales (los resultados parciales <strong>de</strong> sus cálculos), por lo que basta con usar dos <strong>de</strong> los 10<br />

registros temporales disponibles (t0 y t1).<br />

Una vez terminados sus cálculos, la función ha <strong>de</strong> copiar el resultado obt<strong>en</strong>ido al registro<br />

v0 para <strong>de</strong>volverlo a la función llamante. En <strong>MIPS</strong> no existe una instrucción específica para<br />

mover datos <strong>en</strong>tre registros, aunque dicho movimi<strong>en</strong>to se pue<strong>de</strong> realizar sumándole cero al<br />

registro orig<strong>en</strong> y usando el registro <strong>de</strong>stino como resultado <strong>de</strong> la suma. Así, lo que <strong>en</strong> otras<br />

arquitecturas se escribiría como:<br />

move $v0, $t0<br />

En <strong>MIPS</strong> se escribe como:<br />

add $v0, $t0, $zero<br />

Ejercicio<br />

La codificación <strong>de</strong> la función anterior dista bastante <strong>de</strong> ser la óptima, tanto <strong>en</strong> uso <strong>de</strong><br />

registros como <strong>en</strong> número <strong>de</strong> instrucciones. Escriba otra versión <strong>de</strong> la función más efici<strong>en</strong>te.<br />

Llamadas a funciones. La pila<br />

• En algunas arquitecturas exist<strong>en</strong> instrucciones<br />

explícitas para el manejo <strong>de</strong> la pila (push y pop).<br />

• El <strong>MIPS</strong> no ti<strong>en</strong>e soporte explícito <strong>de</strong> la pila sino<br />

una conv<strong>en</strong>ción software:<br />

• Se reserva el registro sp (stack pointer) para<br />

apuntar al “tope” <strong>de</strong> la pila.<br />

• La pila “crece” hacia abajo.<br />

sp<br />

sp<br />

Cont<strong>en</strong>ido ra<br />

Cont<strong>en</strong>ido a0<br />

sp<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 33


Como se ha com<strong>en</strong>tado antes, el uso <strong>de</strong> la pila es imprescindible <strong>en</strong> la llamada a las<br />

funciones. Esto es <strong>de</strong>bido a que sólo es necesario conocer el ord<strong>en</strong> <strong>en</strong> que se han almac<strong>en</strong>ado<br />

los datos, no su posición absoluta y a<strong>de</strong>más pue<strong>de</strong> crecer “in<strong>de</strong>finidam<strong>en</strong>te”; permitiéndose<br />

así el anidami<strong>en</strong>to <strong>de</strong> varias funciones sin que los datos <strong>de</strong> éstas interfieran <strong>en</strong>tre sí.<br />

Aunque muchos procesadores incluy<strong>en</strong> instrucciones específicas para el manejo <strong>de</strong> la<br />

pila (push y pop), el <strong>MIPS</strong> no dispone <strong>de</strong> ellas. No obstante existe una conv<strong>en</strong>ción software<br />

para implantar una pila:<br />

• Se reserva el registro sp (<strong><strong>de</strong>l</strong> inglés stack pointer, puntero <strong>de</strong> pila) para apuntar al<br />

“tope” <strong>de</strong> la pila. Es responsabilidad <strong><strong>de</strong>l</strong> programador el manejo <strong>de</strong> este registro, es<br />

<strong>de</strong>cir, si se introduce o se retira un dato <strong>en</strong> la pila, habrá que modificar el sp para que<br />

continúe apuntando al tope <strong>de</strong> la pila.<br />

• La pila “crece” <strong>de</strong>s<strong>de</strong> posiciones altas <strong>de</strong> memoria hacia posiciones bajas. No hay<br />

ninguna razón para hacerlo así salvo por los preced<strong>en</strong>tes históricos. En consecu<strong>en</strong>cia<br />

el “tope” <strong>de</strong> la pila será la dirección más baja <strong>de</strong> ésta.<br />

En la figura <strong>de</strong> la transpar<strong>en</strong>cia se ilustra la evolución <strong>de</strong> la pila cuando se llama a una<br />

función que necesita guardar dos registros (ra y a0) <strong>en</strong> la pila. Como se pue<strong>de</strong> apreciar <strong>en</strong><br />

primer lugar (figura izquierda) el registro sp estará apuntando al último dato introducido <strong>en</strong><br />

la pila (no mostrado por simplificar). Cuando se llama a la función, ésta necesita guardar<br />

<strong>en</strong> la pila dos registros, por lo que el sp se <strong>de</strong>crem<strong>en</strong>ta <strong>en</strong> dos palabras (8 bytes) y <strong>en</strong> el<br />

espacio creado se copiará el cont<strong>en</strong>ido <strong>de</strong> los dos registros (ra y a0) (figura c<strong>en</strong>tral). Una vez<br />

finalizada la función, la pila ha <strong>de</strong> quedar como estaba, tal como se muestra <strong>en</strong> la figura <strong>de</strong> la<br />

<strong>de</strong>recha.<br />

Llamadas a funciones. Anidami<strong>en</strong>tos<br />

En el ejemplo anterior se mostró una función hoja.<br />

Lam<strong>en</strong>tablem<strong>en</strong>te hay funciones que llaman a otras<br />

funciones.<br />

En estos casos es necesario:<br />

• Guardar la dirección <strong>de</strong> retorno ra<br />

• Guardar los registros (a0-a3 y t0-t9) que se<br />

necesit<strong>en</strong> <strong>de</strong>spués.<br />

Obviam<strong>en</strong>te estos registros se guardan <strong>en</strong> la pila.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 34


En el ejemplo mostrado anteriorm<strong>en</strong>te, la función era una función hoja, es <strong>de</strong>cir, la<br />

función no llamaba a ninguna otra función. Desgraciadam<strong>en</strong>te, no todas las funciones son<br />

funciones hoja, por lo que el mecanismo <strong>de</strong> llamada se complica un poco <strong>en</strong> estos casos.<br />

En concreto, la función llamante ha <strong>de</strong> guardar los registros que la función llamada pueda<br />

modificar:<br />

• El primer registro que se modifica es el registro <strong>de</strong> la dirección <strong>de</strong> retorno ra, ya que<br />

<strong>en</strong> cuanto se ejecute la instrucción jal dicho registro se sobreescribirá con la nueva<br />

dirección <strong>de</strong> retorno. Por tanto, antes <strong>de</strong> llamar a una función es necesario<br />

guardar el valor <strong>de</strong> ra <strong>en</strong> la pila.<br />

• Si la función necesita algún argum<strong>en</strong>to, este ha <strong>de</strong> copiarse <strong>en</strong> los registros a0-a3.<br />

Por tanto, si la función llamante ha <strong>de</strong> usar algún valor <strong>de</strong> estos registros <strong>de</strong>spués <strong>de</strong><br />

la llamada a la función, ha <strong>de</strong> guardar éstos <strong>en</strong> la pila. Nótese que aunque no se<br />

necesite usar alguno <strong>de</strong> los registros a0-a3 para pasar argum<strong>en</strong>tos a la función, ésta<br />

pue<strong>de</strong> llamar a otra función que necesite ese registro como argum<strong>en</strong>to. Por tanto,<br />

siempre se guardarán los registros a0-a3 cuyos valores sean necesarios<br />

<strong>de</strong>spués <strong>de</strong> la llamada a una función.<br />

• Si la función llamante necesita usar algún valor almac<strong>en</strong>ado <strong>en</strong> los registros temporales<br />

t0-t9 <strong>de</strong>spués <strong>de</strong> la llamada a la función, también t<strong>en</strong>drá que guardarlos <strong>en</strong> la<br />

pila antes <strong>de</strong> llamarla.<br />

El ejemplo más complicado <strong>de</strong> función no hoja es una función recursiva. En la sigui<strong>en</strong>te<br />

transpar<strong>en</strong>cia se muestra una función para calcular el factorial <strong>de</strong> forma recursiva. Aunque<br />

este es el peor ejemplo <strong>de</strong> uso <strong>de</strong> la recursividad, pues es mucho más efici<strong>en</strong>te resolverlo con<br />

un bucle, su simplicidad justifica su uso <strong>en</strong> este caso.<br />

Llamadas a funciones. Ejemplo<br />

int fact(int n)<br />

{<br />

if (n < 1){<br />

return 1;<br />

}else{<br />

return n * fact(n-1);<br />

}<br />

}<br />

Se traduce <strong>en</strong> (n se pasa <strong>en</strong> el registro a0):<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 35


Llamadas a funciones. Ejemplo<br />

fact: slti $t0, $a0, 1 # n=1, a L1<br />

addi $v0, $zero, 1 # <strong>de</strong>vuelve 1<br />

jr $ra<br />

L1: addi $sp, $sp, -8 # Reserva 2 palabras <strong>en</strong> pila<br />

sw $ra, 4($sp) # guarda ra y<br />

sw $a0, 0($sp) # n <strong>en</strong> pila<br />

addi $a0, $a0, -1 # a0=n-1<br />

jal fact<br />

lw $a0, 0($sp) # restaura n<br />

lw $ra, 4($sp) # y ra<br />

addi $sp, $sp, 8 # ajusta sp<br />

mul $v0, $a0, $v0 # <strong>de</strong>vuelve<br />

jr $ra # n * fact(n-1)<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 36<br />

Al igual que el programa <strong>en</strong> C, lo primero que realiza la función es comprobar si su<br />

argum<strong>en</strong>to n (a0) es m<strong>en</strong>or que 1 para <strong>en</strong> caso afirmativo <strong>de</strong>volver un 1. Para realizar la<br />

comparación se ha usado una versión <strong>de</strong> la instrucción slt d<strong>en</strong>ominada slti (<strong><strong>de</strong>l</strong> inglés set<br />

on less than inmediate). El funcionami<strong>en</strong>to es idéntico a la instrucción slt salvo que <strong>en</strong> lugar<br />

<strong>de</strong> comparar dos registros, compara un registro con una constante. Por tanto la instrucción:<br />

slti $t0, $a0, 1 # n


sw $ra, 4($sp) # guarda ra y<br />

sw $a0, 0($sp) # n <strong>en</strong> pila<br />

La estructura <strong>de</strong> la pila <strong>en</strong> este instante será la mostrada <strong>en</strong> la figura <strong>de</strong> la transpar<strong>en</strong>cia<br />

33. Una vez salvados los dos registros, se pasa a llamar a la función fact. Para ello, se<br />

sitúa <strong>en</strong> el registro a0 el valor n-1, lo cual se hace restando 1 a dicho registro, ya que éste<br />

cont<strong>en</strong>ía el valor <strong>de</strong> n. Una vez hecho esto ya se pue<strong>de</strong> llamar a la función fact mediante la<br />

instrucción jal:<br />

addi $a0, $a0, -1 # a0=n-1<br />

jal fact<br />

Cuando dicha función <strong>de</strong>vuelva el control, <strong>en</strong> el registro v0 estará almac<strong>en</strong>ado el valor <strong>de</strong><br />

(n-1)!. Por tanto, lo único que hay que hacer es restaurar los registros que se almac<strong>en</strong>aron<br />

<strong>en</strong> la pila y calcular n*(n-1)! para <strong>de</strong>volverlo. La restauración <strong>de</strong> registros es el proceso<br />

inverso al realizado para guardarlos:<br />

lw $a0, 0($sp) # restaura n<br />

lw $ra, 4($sp) # y ra<br />

addi $sp, $sp, 8 # ajusta sp<br />

Como se pue<strong>de</strong> apreciar, <strong>de</strong>spués <strong>de</strong> la ejecución <strong>de</strong> estas instrucciones la pila se quedará<br />

como estaba antes <strong>de</strong> llamar a la función. Lo único que resta por hacer es calcular n*(n-1)!<br />

y <strong>de</strong>volver el control a la función llamante, lo cual se realiza mediante:<br />

mult $v0, $a0, $v0 # <strong>de</strong>vuelve<br />

jr $ra # n * fact(n-1)<br />

Ejercicio<br />

Escriba un programa <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong> para calcular el factorial <strong>de</strong> 7. Utilice<br />

para ello la función fact <strong>de</strong>sarrollada anteriorm<strong>en</strong>te.<br />

36-3


Llamadas a funciones. Bloque <strong>de</strong> activación<br />

La pila crece y <strong>de</strong>crece durante la ejecución <strong>de</strong> la<br />

función para:<br />

• Almac<strong>en</strong>ar variables locales.<br />

• Evaluar expresiones.<br />

• Guardar registros.<br />

El segm<strong>en</strong>to <strong>de</strong> la pila que conti<strong>en</strong>e todos los datos <strong>de</strong><br />

una función se d<strong>en</strong>omina bloque <strong>de</strong> activación<br />

Algunos programas usan el registro fp para apuntar al<br />

principio <strong><strong>de</strong>l</strong> bloque <strong>de</strong> activación.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 37<br />

Durante la ejecución <strong>de</strong> la función la pila pue<strong>de</strong> crecer y <strong>de</strong>crecer. Por ejemplo si se<br />

<strong>de</strong>clara una estructura como variable local, ésta t<strong>en</strong>drá que almac<strong>en</strong>arse <strong>en</strong> la pila, para lo<br />

que será necesario <strong>de</strong>crem<strong>en</strong>tar el sp <strong>en</strong> el número <strong>de</strong> palabras que ocupe dicha estructura.<br />

A<strong>de</strong>más algunos programas necesitan usar la pila para evaluar expresiones matemáticas complejas.<br />

Por si esto fuera poco, algunos l<strong>en</strong>guajes como C++ permit<strong>en</strong> crear variables locales<br />

<strong>en</strong> cualquier punto <strong>de</strong> la función, por lo que la pila pue<strong>de</strong> crecer <strong>en</strong> cualquier mom<strong>en</strong>to. Esto<br />

hace que si se usa el registro sp para acce<strong>de</strong>r a las variables almac<strong>en</strong>adas <strong>en</strong> la pila, será necesario<br />

utilizar <strong>de</strong>splazami<strong>en</strong>tos distintos a lo largo <strong>de</strong> la función, dificultándose la escritura<br />

<strong><strong>de</strong>l</strong> programa.<br />

Por tanto, es conv<strong>en</strong>i<strong>en</strong>te t<strong>en</strong>er una refer<strong>en</strong>cia a las variables almac<strong>en</strong>adas <strong>en</strong> la pila<br />

que no varíe durante la ejecución <strong>de</strong> la función. Algunos programas <strong>MIPS</strong> usan el registro<br />

fp para almac<strong>en</strong>ar la primera palabra <strong><strong>de</strong>l</strong> bloque <strong>de</strong> la pila usado por la función, al que se<br />

d<strong>en</strong>omina bloque <strong>de</strong> activación. Por ello al registro fp se le conoce como puntero al bloque<br />

<strong>de</strong> activación (frame pointer). Dicho registro se carga con el valor <strong><strong>de</strong>l</strong> sp al iniciar la función<br />

y no varía hasta que ésta termine. Por tanto, los accesos a las variables almac<strong>en</strong>adas <strong>en</strong> la<br />

pila pued<strong>en</strong> referirse al fp y dichas refer<strong>en</strong>cias no t<strong>en</strong>drán que cambiarse cada vez que se<br />

introduzca o elimine algún dato <strong>de</strong> la pila.<br />

Ejercicio<br />

El uso <strong><strong>de</strong>l</strong> puntero al bloque <strong>de</strong> activación facilita a<strong>de</strong>más la restauración <strong><strong>de</strong>l</strong> puntero <strong>de</strong><br />

pila al final <strong>de</strong> la ejecución <strong>de</strong> la función. Escriba las instrucciones necesarias para guardar<br />

el principio <strong><strong>de</strong>l</strong> bloque <strong>de</strong> activación <strong>en</strong> fp al principio <strong>de</strong> la función y para restaurar el sp al<br />

finalizar la función.


Llamadas a funciones. Paso <strong>de</strong> arg. por pila<br />

Si hay más <strong>de</strong> 4 parámetros o alguno <strong>de</strong> éstos no<br />

cabe <strong>en</strong> registros se pasan por la pila.<br />

Conv<strong>en</strong>ción software: se sitúan por <strong>en</strong>cima <strong><strong>de</strong>l</strong> bloque<br />

<strong>de</strong> activación.<br />

fp<br />

sp<br />

Bloque<br />

Activación<br />

fp<br />

sp<br />

Argum<strong>en</strong>tos<br />

Bloque<br />

Activación<br />

fp<br />

sp<br />

Bloque<br />

Activación<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 38<br />

Según se ha dicho anteriorm<strong>en</strong>te, hay ocasiones <strong>en</strong> las cuales los 4 registros reservados<br />

para el paso <strong>de</strong> argum<strong>en</strong>tos <strong>en</strong>tre funciones (a0-a3) no son sufici<strong>en</strong>tes:<br />

• Si hay más <strong>de</strong> 4 argum<strong>en</strong>tos. En este caso los 4 primeros se pasan <strong>en</strong> los registros y<br />

los restantes <strong>en</strong> la pila.<br />

• Si algún o algunos argum<strong>en</strong>tos no cab<strong>en</strong> <strong>en</strong> un registro. En este caso los argum<strong>en</strong>tos<br />

que no quepan se pasan por la pila.<br />

En estos casos, los argum<strong>en</strong>tos se sitúan justo <strong>en</strong>cima <strong><strong>de</strong>l</strong> bloque <strong>de</strong> activación <strong>de</strong> la función<br />

llamada (o visto <strong>de</strong> otra manera, al final <strong><strong>de</strong>l</strong> bloque <strong>de</strong> activación <strong>de</strong> la función llamante).<br />

Para acce<strong>de</strong>r a ellos, lo más conv<strong>en</strong>i<strong>en</strong>te es usar el puntero al bloque <strong>de</strong> actuvación fp.<br />

Ejercicios<br />

1. Escriba la sigui<strong>en</strong>te función <strong>en</strong> C <strong>en</strong> <strong>en</strong>samblador <strong>MIPS</strong>:<br />

int suma(int a, int b, int c, int d, int e, int f){<br />

return a+b+c+d+e+f;<br />

}<br />

2. Escriba la secu<strong>en</strong>cia <strong>de</strong> intrucciones <strong>de</strong> <strong>en</strong>samblador <strong>MIPS</strong> para sumar los valores<br />

almac<strong>en</strong>ados <strong>en</strong> los 6 registros s0-s5 mediante una llamada a la función suma. El<br />

resultado se guardará <strong>en</strong> el registro s6.


Manejo <strong>de</strong> caracteres<br />

Los caracteres se codifican <strong>en</strong> ASCII.<br />

Un carácter ASCII ocupa 1 byte.<br />

El <strong>MIPS</strong> dispone <strong>de</strong> dos instrucciones para cargar y<br />

almac<strong>en</strong>ar bytes:<br />

• lb (load byte). Lee un byte <strong>de</strong> la memoria y lo<br />

almac<strong>en</strong>a <strong>en</strong> los 8 bits m<strong>en</strong>os significativos <strong><strong>de</strong>l</strong><br />

registro <strong>de</strong>stino. Ej. lb $t0, 0($s0).<br />

• sb (store byte). Almac<strong>en</strong>a los 8 bits m<strong>en</strong>os<br />

significativos <strong><strong>de</strong>l</strong> registro orig<strong>en</strong> <strong>en</strong> la memoria.<br />

Ej. sb $t0, 0($s0).<br />

Los caracteres pued<strong>en</strong> estar <strong>en</strong> cualquier posición <strong>de</strong><br />

memoria.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 39<br />

La mayoría <strong>de</strong> las aplicaciones informáticas necesitan procesar caracteres. Exist<strong>en</strong> varios<br />

métodos <strong>de</strong> codificación, aunque el más ext<strong>en</strong>dido es el ASCII, <strong>en</strong> el cual un carácter ocupa<br />

un byte.<br />

El <strong>MIPS</strong> dispone <strong>de</strong> dos instrucciones para cargar y almac<strong>en</strong>ar bytes: lb y sb. El funcionami<strong>en</strong>to<br />

<strong>de</strong> ambas instrucciones es análogo a lw y sw, excepto que sólo le<strong>en</strong> un byte <strong>de</strong><br />

la memoria y lo almac<strong>en</strong>an <strong>en</strong> los 8 bits m<strong>en</strong>os significativos <strong><strong>de</strong>l</strong> registro <strong>de</strong>stino. A<strong>de</strong>más el<br />

byte pue<strong>de</strong> estar situado <strong>en</strong> cualquier posición <strong>de</strong> memoria.


Manejo <strong>de</strong> caracteres. Ejemplo<br />

El sigui<strong>en</strong>te ejemplo muestra la función strcpy <strong>de</strong> C:<br />

void strcpy(char <strong>de</strong>st[], char orig[])<br />

{<br />

int i;<br />

i = 0;<br />

/*Copia y comprueba final*/<br />

while( (<strong>de</strong>st[i] = orig[i]) != NULL){<br />

i++;<br />

}<br />

}<br />

¿Cuál es la traducción a <strong>en</strong>samblador <strong>MIPS</strong><br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 40<br />

En la transpar<strong>en</strong>cia se muestra una implem<strong>en</strong>tación <strong>de</strong> la función strcpy <strong>de</strong> la librería<br />

estándar <strong>de</strong> C. Dicha función copia una cad<strong>en</strong>a oríg<strong>en</strong> (orig) <strong>en</strong> otra cad<strong>en</strong>a <strong>de</strong>stino (<strong>de</strong>st).<br />

Ambas cad<strong>en</strong>as sigu<strong>en</strong> la conv<strong>en</strong>ción <strong>de</strong> C para indicar su final mediante el carácter nulo<br />

(NULL).<br />

La función copia el caracter i <strong>de</strong> la cad<strong>en</strong>a oríg<strong>en</strong> <strong>en</strong> la posición i <strong>de</strong> la cad<strong>en</strong>a <strong>de</strong>stino<br />

y <strong>de</strong>spúes comprueba si éste es distinto <strong>de</strong> NULL. Si no lo es increm<strong>en</strong>ta el índice y continúa<br />

el bucle. Cuando el carácter copiado sea el terminador nulo <strong>de</strong> la cad<strong>en</strong>a, el bucle terminará,<br />

aunque <strong>de</strong>spués <strong>de</strong> copiar el NULL a la cad<strong>en</strong>a <strong>de</strong> <strong>de</strong>stino, con lo que ésta será correcta.<br />

En la sigui<strong>en</strong>te transpar<strong>en</strong>cia se muestra el código <strong>en</strong> <strong>en</strong>samblador <strong>MIPS</strong> para implem<strong>en</strong>tar<br />

esta misma función.


Manejo <strong>de</strong> caracteres. Ejemplo<br />

strcpy:<br />

add $t0, $zero, $zero # i = 0<br />

L1: add $t1, $t0, $a1 # t1=dir(orig[i])<br />

lb $t2, 0($t1) # t2 = orig[i]<br />

add $t3, $t0, $a0 # t3=dir(<strong>de</strong>st[i])<br />

sb $t2, 0($t3) # <strong>de</strong>st[i] = t2<br />

add $t0, $t0, 1 # i++<br />

bne $t2, $zero, L1<br />

jr $ra<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 41<br />

La primera instrucción símplem<strong>en</strong>te pone a cero el registro t0, que va a ser usado para<br />

almac<strong>en</strong>ar el índice i. Nótese que dicha operación se hace almac<strong>en</strong>ando el resultado <strong>de</strong> sumar<br />

0+0.<br />

La sigui<strong>en</strong>te instrucción calcula la dirección <strong><strong>de</strong>l</strong> carácter <strong>de</strong> la cad<strong>en</strong>a orig<strong>en</strong> que se va a<br />

copiar. Para ello se suma el índice i a la base <strong>de</strong> la cad<strong>en</strong>a, que según pue<strong>de</strong> <strong>de</strong>spr<strong>en</strong><strong>de</strong>rse <strong><strong>de</strong>l</strong><br />

código <strong>en</strong> C, estará almac<strong>en</strong>ado <strong>en</strong> el registro a1, pues es el segundo argum<strong>en</strong>to <strong>de</strong> la función.<br />

Una vez calculada la dirección, se pue<strong>de</strong> usar la instrucción lb para cargar el carácter <strong>en</strong> el<br />

registro t2, que es lo que se hace <strong>en</strong> la tercera instrucción.<br />

A continuación se calcula la dirección <strong>en</strong> la que hay que almac<strong>en</strong>ar el carácter, que será<br />

el resultado <strong>de</strong> sumar el índice i a la base <strong>de</strong> la cad<strong>en</strong>a <strong>de</strong>stino (almac<strong>en</strong>ada <strong>en</strong> a0) y se<br />

almac<strong>en</strong>a el carácter <strong>en</strong> dicha dirección mediante la instrucción sb<br />

Por último se increm<strong>en</strong>ta el índice y se salta al principio <strong><strong>de</strong>l</strong> bucle si el carácter es distinto<br />

<strong>de</strong> cero (recuer<strong>de</strong> que <strong>en</strong> C NULL es un 0). Si se <strong>en</strong>cu<strong>en</strong>tra el terminador nulo <strong>de</strong> la cad<strong>en</strong>a, no<br />

se producirá el salto y se <strong>de</strong>vuelve el control mediante la instrucción jr.<br />

Ejercicios<br />

1. ¿Por qué no hace falta multiplicar por 4 el índice <strong>de</strong> la cad<strong>en</strong>a<br />

2. La codificación <strong>en</strong> <strong>en</strong>samblador no refleja exáctam<strong>en</strong>te el código C <strong>de</strong> la función.<br />

¿Por qué Codifique una función que refleje exáctam<strong>en</strong>te el código C y compare<br />

su efici<strong>en</strong>cia con la mostrada <strong>en</strong> la transpar<strong>en</strong>cia. Indique para ello el número <strong>de</strong><br />

instrucciones ejecutadas <strong>en</strong> cada versión <strong>de</strong> la función si se copia una cad<strong>en</strong>a <strong>de</strong> 80<br />

caracteres.


Aritmética. Números con y sin signo<br />

El <strong>MIPS</strong> trabaja con “ristras” <strong>de</strong> 8, 16 o 32 bits.<br />

Estas ristras <strong>de</strong> bits pued<strong>en</strong> repres<strong>en</strong>tar, <strong>en</strong>tre otras<br />

cosas:<br />

• Un número sin signo (rango 0 ↔ 2 n − 1).<br />

• Un número con signo <strong>en</strong> complem<strong>en</strong>to a 2 (rango<br />

−2 n−1 ↔ 2 n−1 − 1).<br />

Tanto las instrucciones aritméticas como las <strong>de</strong> carga<br />

y comparación han <strong>de</strong> distinguir si sus operandos son<br />

con o sin signo.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 42<br />

El procesador es una máquina capaz <strong>de</strong> procesar “ristras” <strong>de</strong> dígitos binarios. En el caso<br />

<strong><strong>de</strong>l</strong> <strong>MIPS</strong>, éste pue<strong>de</strong> trabajar con “ristras” <strong>de</strong> 8, 16 y 32 bits. El significado <strong>de</strong> dichas “ristras”<br />

<strong>de</strong> bits es totalm<strong>en</strong>te indifer<strong>en</strong>te para el procesador, 1 si<strong>en</strong>do responsabilidad <strong><strong>de</strong>l</strong> programador<br />

su interpretación.<br />

Cuando se trabaja con números <strong>en</strong>teros, éstos pued<strong>en</strong> consi<strong>de</strong>rarse como números sin<br />

signo, con lo cual podremos repres<strong>en</strong>tar números <strong>en</strong> el rango <strong>de</strong> 0 a 2 n − 1. o bi<strong>en</strong> como<br />

números codificados <strong>en</strong> complem<strong>en</strong>to a dos (rango <strong>de</strong> −2 n−1 a 2 n−1 − 1). Ahora bi<strong>en</strong>, la<br />

forma <strong>de</strong> operar con ambos tipos <strong>de</strong> números es distinta, por lo que se usan instrucciones<br />

distintas según el tipo <strong>de</strong> datos utilizados. Así, las instrucciones aritméticas, <strong>de</strong> carga y <strong>de</strong><br />

comparación son distintas según oper<strong>en</strong> con datos sin signo o con signo.<br />

En el caso <strong>de</strong> los l<strong>en</strong>guajes <strong>de</strong> alto nivel como C, al <strong>de</strong>clarar una variable se informa al<br />

sistema <strong><strong>de</strong>l</strong> tipo <strong>de</strong> ésta. Así, para crear un <strong>en</strong>tero con signo se <strong>de</strong>clara como int y sin signo<br />

como unsigned int. Es <strong>en</strong>tonces tarea <strong><strong>de</strong>l</strong> compilador elegir las operaciones necesarias<br />

para operar correctam<strong>en</strong>te con los datos. En cambio, cuando se programa <strong>en</strong> <strong>en</strong>samblador,<br />

esta tarea recae <strong>en</strong> el programador.<br />

1 Salvo <strong>en</strong> el caso <strong>en</strong> que dihas “ristras” <strong>de</strong> bits sean parte <strong>de</strong> un programa.


Aritmética. Números con y sin signo<br />

Cuando se carga un número con signo <strong>de</strong> 16 u 8 bits<br />

<strong>en</strong> un registro <strong>de</strong> 32, es necesario ext<strong>en</strong><strong>de</strong>r el bit <strong>de</strong><br />

signo. Ej:<br />

• -1 <strong>en</strong> 8 bits es 11111111<br />

• -1 <strong>en</strong> 16 bits es 11111111 11111111<br />

• -1 <strong>en</strong> 32 bits es 11111111 11111111 11111111<br />

11111111<br />

Esta ext<strong>en</strong>sión es necesaria porque los circuitos<br />

aritméticos operan sólo con números <strong>de</strong> 32 bits.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 43<br />

Aritmética. Números con y sin signo<br />

Cuando se carga un número sin signo <strong>de</strong> 16 u 8 bits<br />

<strong>en</strong> un registro <strong>de</strong> 32, no hay que ext<strong>en</strong><strong>de</strong>r el bit <strong>de</strong><br />

signo. Ej:<br />

• 255 <strong>en</strong> 8 bits es 11111111<br />

• 255 <strong>en</strong> 32 bits es 00000000 00000000 00000000<br />

11111111<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 44


Aritmética. Números con y sin signo<br />

Las instrucciones <strong>de</strong> carga vistas hasta ahora cargan<br />

números con signo:<br />

• lb carga un byte ext<strong>en</strong>di<strong>en</strong>do el signo.<br />

• lh carga una media palabra (16 bits)<br />

ext<strong>en</strong>di<strong>en</strong>do el signo. La media palabra ha <strong>de</strong><br />

estar <strong>en</strong> una dirección par.<br />

• lw carga una palabra. No ti<strong>en</strong>e s<strong>en</strong>tido ext<strong>en</strong><strong>de</strong>r<br />

el signo, pues no hay más bits.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 45<br />

Debido a que internam<strong>en</strong>te el <strong>MIPS</strong> siempre realiza las operaciones con 32 bits, cuando<br />

se carga un dato <strong>de</strong> 8 o 16 bits <strong>en</strong> un registro, es necesario que la cantidad repres<strong>en</strong>tada por<br />

los 32 bits sea la misma que la repres<strong>en</strong>tada por los 8 o los 16 bits que se han cargado. Si<br />

las cantida<strong>de</strong>s almac<strong>en</strong>adas <strong>en</strong> 8 o 16 bits son sin signo, basta con copiar esos 8 o 16 bits <strong>en</strong><br />

los 8 o 16 bits m<strong>en</strong>os significativos <strong><strong>de</strong>l</strong> registro <strong>de</strong> 32 bits. Ahora bi<strong>en</strong>, si los números <strong>de</strong> 8<br />

o 16 bits son con signo, es necesario copiar el bit <strong>de</strong> signo <strong>en</strong> los bits superiores <strong><strong>de</strong>l</strong> registro<br />

<strong>de</strong> 32 bits para que se mant<strong>en</strong>ga el signo <strong><strong>de</strong>l</strong> número. Así, si t<strong>en</strong>emos almac<strong>en</strong>ado <strong>en</strong> una<br />

variable <strong>de</strong> 8 bits con signo el valor 11111110 (-2), al copiar dicha variable <strong>en</strong> un registro <strong>de</strong><br />

32 bits, habrá que copiar el bit <strong>de</strong> signo <strong>en</strong> los bits 9 a 31 para que el número almac<strong>en</strong>ado<br />

<strong>en</strong> el registro sea también un -2. En cambio, si t<strong>en</strong>emos almac<strong>en</strong>ado un número sin signo,<br />

por ejemplo 11111110 (254), al copiar este número <strong>en</strong> un registro <strong>de</strong> 32 bits no habrá que<br />

ext<strong>en</strong><strong>de</strong>r el “bit signo” para que se almac<strong>en</strong>e el 254 correctam<strong>en</strong>te <strong>en</strong> el registro <strong>de</strong> 32 bits.<br />

Las instruciones <strong>de</strong> carga vistas hasta ahora (lb y lw) trabajan con números con signo.<br />

En el caso <strong>de</strong> lw no ti<strong>en</strong>e s<strong>en</strong>tido hacer ninguna distinción, pues carga un número <strong>de</strong> 32 bits<br />

<strong>en</strong> un registro <strong>de</strong> 32 bits y por tanto no hay que hacer ext<strong>en</strong>sión <strong>de</strong> signo.<br />

A<strong>de</strong>más <strong>de</strong> estas dos instrucciones <strong>de</strong> carga existe una tercera lh que carga media palabra<br />

(16 bits) <strong>en</strong> los 16 bits m<strong>en</strong>os significativos <strong>de</strong> un registro, ext<strong>en</strong>di<strong>en</strong>do el bit <strong>de</strong> signo. Por<br />

ejemplo, para cargar <strong>en</strong> t0 una media palabra cuya dirección está almac<strong>en</strong>ada <strong>en</strong> el registro<br />

s0, basta con ejecutar la instrucción:<br />

lh $t0, 0($s0)<br />

Las medias palabras han <strong>de</strong> estar alineadas <strong>en</strong> posiciones <strong>de</strong> memoria múltiplos <strong>de</strong> 2.


Aritmética. Números con y sin signo<br />

Las instrucciones <strong>de</strong> carga para números sin signo<br />

son:<br />

• lbu carga un byte sin ext<strong>en</strong><strong>de</strong>r el signo.<br />

• lhu carga una media palabra (16 bits) sin<br />

ext<strong>en</strong><strong>de</strong>r el signo.<br />

• lw carga una palabra. No ti<strong>en</strong>e s<strong>en</strong>tido ext<strong>en</strong><strong>de</strong>r<br />

el signo, pues no hay más bits.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 46<br />

Las instrucciones para cargar números sin signo son iguales que las correspondi<strong>en</strong>tes<br />

para números con signo, salvo que su nemónico termina <strong>en</strong> u (<strong>de</strong> unsigned).<br />

Aunque no se m<strong>en</strong>ciona <strong>en</strong> la transpar<strong>en</strong>cia, la media palabra a cargar con lhu ha <strong>de</strong><br />

estar almac<strong>en</strong>ada <strong>en</strong> una dirección par.<br />

Al igual que antes, no ti<strong>en</strong>e s<strong>en</strong>tido distinguir <strong>en</strong>tre números con signo o sin signo para<br />

la carga <strong>de</strong> palabras <strong>de</strong> 32 bits, pues no hay que ext<strong>en</strong><strong>de</strong>r ningún bit <strong>de</strong> signo.


Aritmética. Números con y sin signo<br />

Las instrucciones <strong>de</strong> comparación son distintas para<br />

números con signo o sin signo:<br />

• slt compara dos números con signo.<br />

• sltu compara dos números sin signo.<br />

• slti Compara un registro con una constante.<br />

Ambas con signo.<br />

• sltiu Compara un registro con una constante.<br />

Ambas sin signo.<br />

Ej: slti $t0, $s0, -7<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 47<br />

La comparación <strong>en</strong>tre dos números <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong> si éstos son con signo o sin signo. Por<br />

tanto el <strong>MIPS</strong> dispone <strong>de</strong> versiones <strong>de</strong> las instrucciones <strong>de</strong> comparación para ambos tipos <strong>de</strong><br />

datos.<br />

Al igual que antes, las instrucciones estudiadas hasta ahora comparan números con signo.<br />

Para comparar números sin signo el formato <strong>de</strong> las instrucciones es el mismo salvo que el<br />

nemónico termina <strong>en</strong> una u (<strong>de</strong> unsigned).


Aritmética. Números con y sin signo<br />

Ejemplo:<br />

• s0 = 11111111 11111111 11111111 11111111<br />

• s1 = 00000000 00000000 00000000 00000001<br />

¿Cuanto val<strong>en</strong> t0 y t1 <strong>de</strong>spués <strong>de</strong> ejecutar las<br />

instrucciones<br />

slt $t0, $s0, $s1 # Con signo<br />

sltu $t1, $s0, $s1 # Sin signo<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 48<br />

En el ejemplo, el registro s0 vale -1 si se interpreta como un número <strong>en</strong> complem<strong>en</strong>to a<br />

2 ó 4.294.967.295 si se interpreta como un número sin signo. El registro s1, <strong>en</strong> cambio, vale<br />

1 in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>tem<strong>en</strong>te <strong>de</strong> cómo se interprete.<br />

En la primera instrucción se realiza la comparación con signo. Por tanto, como −1 < 1,<br />

t0 se pondrá a 1.<br />

En cambio, <strong>en</strong> la segunda instrucción se realiza la comparación sin signo, por lo que<br />

como 4,294,967,295 > 1, t1 se pondrá a 0.


Aritmética. Suma y resta<br />

En las instrucciones <strong>de</strong> suma y resta pue<strong>de</strong> ser<br />

necesario saber si ha existido un <strong>de</strong>sbordami<strong>en</strong>to.<br />

• En los números sin signo, utilizados para<br />

aritmética <strong>de</strong> direcciones, se ignora.<br />

• En los números con signo, <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong> la<br />

aplicación, pue<strong>de</strong> ser necesario <strong>de</strong>tectarlo.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 49<br />

Al realizar una suma o una resta <strong>de</strong> dos números <strong>de</strong> 32 bits, el resultado pue<strong>de</strong> necesitar<br />

33 bits si ambos números son <strong>de</strong>masiado gran<strong>de</strong>s. Como el resultado se almac<strong>en</strong>a <strong>en</strong> un<br />

registro <strong>de</strong> 32 bits, el bit más significativo se pier<strong>de</strong>. En estos casos se dice que se ha producido<br />

un <strong>de</strong>sbordami<strong>en</strong>to (overflow <strong>en</strong> inglés).<br />

El uso fundam<strong>en</strong>tal <strong>de</strong> los números sin signo es la realización <strong>de</strong> operaciones con direcciones,<br />

<strong>en</strong> las cuales no se suele <strong>de</strong>tectar el <strong>de</strong>sbordami<strong>en</strong>to. En cambio, los números con<br />

signo suel<strong>en</strong> usarse <strong>en</strong> operaciones matemáticas, <strong>en</strong> las que, <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong> la aplicación,<br />

pue<strong>de</strong> ser necesario <strong>de</strong>tectar si se ha producido un <strong>de</strong>sbordami<strong>en</strong>to.<br />

La mayoría <strong>de</strong> los procesadores dispon<strong>en</strong> <strong>de</strong> dos bits <strong>en</strong> el registro <strong>de</strong> estado para indicar<br />

si se ha producido un <strong>de</strong>sbordami<strong>en</strong>to:<br />

• El bit <strong>de</strong> accarreo (carry <strong>en</strong> inglés), el cual se pone a 1 cuando se produce un<br />

<strong>de</strong>sbordami<strong>en</strong>to <strong>en</strong> la suma sin signo.<br />

• El bit <strong>de</strong> <strong>de</strong>sbordami<strong>en</strong>to (overflow), el cual se pone a 1 cuando se produce un <strong>de</strong>sbordami<strong>en</strong>to<br />

<strong>en</strong> la suma con signo.<br />

En estos procesadores se incluy<strong>en</strong> a<strong>de</strong>más instrucciones <strong>de</strong> salto condicional que saltan si<br />

alguno <strong>de</strong> estos bits está a 1. Por tanto, para <strong>de</strong>tectar un <strong>de</strong>sbordami<strong>en</strong>to basta con ejecutar la<br />

instrucción <strong>de</strong> salto condicional justo <strong>de</strong>spués <strong>de</strong> la operación aritmética cuyo <strong>de</strong>sbordami<strong>en</strong>to<br />

queremos comprobar. De esta forma el programa pue<strong>de</strong> ejecutar una serie <strong>de</strong> isntrucciones<br />

u otras <strong>en</strong> función <strong>de</strong> si se ha producido o no un <strong>de</strong>sbordami<strong>en</strong>to. En el <strong>MIPS</strong>, según se<br />

muestra <strong>en</strong> la sigui<strong>en</strong>te transpar<strong>en</strong>cia, la solución adoptada es radicalm<strong>en</strong>te distinta.


Aritmética. Suma y resta<br />

<strong>MIPS</strong> dispone <strong>de</strong> dos tipos <strong>de</strong> instrucciones para la<br />

suma y la resta <strong>en</strong> función <strong><strong>de</strong>l</strong> tratami<strong>en</strong>to <strong><strong>de</strong>l</strong><br />

<strong>de</strong>sbordami<strong>en</strong>to.<br />

• add, addi, sub, g<strong>en</strong>eran una excepción si se<br />

produce un <strong>de</strong>sbordami<strong>en</strong>to.<br />

• addu, addiu, subu no g<strong>en</strong>eran excepciones <strong>en</strong><br />

caso <strong>de</strong> <strong>de</strong>sbordami<strong>en</strong>to.<br />

Las instrucciones <strong>de</strong> suma se han estudiado antes. La<br />

instrucción sub $t0, $s0, $s1 resta s0-s1 y<br />

almac<strong>en</strong>a el resultado <strong>en</strong> t0.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 50<br />

El <strong>MIPS</strong> dispone <strong>de</strong> dos tipos <strong>de</strong> instrucciones aritméticas: unas que ti<strong>en</strong><strong>en</strong> <strong>en</strong> cu<strong>en</strong>ta el<br />

<strong>de</strong>sbordami<strong>en</strong>to y otras que lo ignoran.<br />

Las instrucciones add, addi y sub g<strong>en</strong>eran una excepción si se produce un <strong>de</strong>sbordami<strong>en</strong>to.<br />

Una excepción es una llamada a una función no planificada, es <strong>de</strong>cir, que sólo ocurre<br />

cuando se da una situación excepcional, como es un <strong>de</strong>sbordami<strong>en</strong>to <strong>en</strong> este caso. Así, cuando<br />

al ejecutar alguna <strong>de</strong> estas instrucciones se produce un <strong>de</strong>sbordami<strong>en</strong>to, la dirección <strong>de</strong><br />

la instrucción que ha provocado el <strong>de</strong>sbordami<strong>en</strong>to se sitúa <strong>en</strong> un registro especial y la ejecución<br />

<strong><strong>de</strong>l</strong> programa salta a una direción pre<strong>de</strong>finida <strong>en</strong> la que se <strong>en</strong>contrará una rutina <strong>de</strong><br />

at<strong>en</strong>ción <strong>de</strong> la excepción. Esta rutina podrá infomar al usuario <strong><strong>de</strong>l</strong> error y abortar el programa<br />

o int<strong>en</strong>tar tomar medidas correctoras y continuar el programa <strong>de</strong>spués <strong>de</strong> la instrucción que<br />

causó el <strong>de</strong>sbordami<strong>en</strong>to.<br />

Por otro lado, las instrucciones addu, addiu y subu realizan las mismas operaciones que<br />

sus versiones con signo salvo que no g<strong>en</strong>eran una excepción si se produce un <strong>de</strong>sbordami<strong>en</strong>to.<br />

El formato <strong>de</strong> la instrucción <strong>de</strong> resta es sub <strong>de</strong>st, orig1, orig2. Esta instrucción<br />

resta el cont<strong>en</strong>ido <strong>de</strong> los registros orig1-orig2 y <strong>de</strong>posita el resultado <strong>en</strong> el registro <strong>de</strong>st.<br />

Nótese que no existe la instrucción subi. Esto es <strong>de</strong>bido a que la instrucción addi suma a<br />

un registro una constante <strong>de</strong> 16 bits con signo, por lo que para restar una constante basta<br />

con sumar dicha constante cambiada <strong>de</strong> signo. Convi<strong>en</strong>e <strong>de</strong>stacar que tanto las instrucciones<br />

addi como addiu exti<strong>en</strong>d<strong>en</strong> siempre el signo <strong>de</strong> su constante <strong>de</strong> 16 bits antes <strong>de</strong> realizar la<br />

operación. Como se ha dicho antes la única difer<strong>en</strong>cia <strong>en</strong>tre las operaciones “sin signo” y las<br />

“con signo” es que las primeras no g<strong>en</strong>eran excepciones y las segundas sí.<br />

Como se ha dicho antes, otras arquitecturas pose<strong>en</strong> instrucciones <strong>de</strong> salto condicional<br />

<strong>en</strong> función <strong>de</strong> si se ha producido o no un <strong>de</strong>sbordami<strong>en</strong>to. Lam<strong>en</strong>tablem<strong>en</strong>te el <strong>MIPS</strong> no<br />

dispone <strong>de</strong> dicha instrucción, por lo que si queremos <strong>de</strong>tectar el <strong>de</strong>sbordami<strong>en</strong>to sin utilizar


excepciones, es necesario realizarlo mediante una secu<strong>en</strong>cia <strong>de</strong> instrucciones, tal como se<br />

muestra a continuación<br />

50-2<br />

Aritmética. Suma y resta<br />

addu $t0, $t1, $t2 # suma sin <strong>de</strong>sbordami<strong>en</strong>to<br />

xor $t3, $t1, $t2 # signos distintos<br />

slt $t3, $t3, $zero #si t3 no <strong>de</strong>sb.<br />

xor $t3, $t0, $t1 # si signos iguales<br />

slt $t3, $t3, $zero # ¿suma también<br />

bne $t3, $zero, Desb # Si sign(suma)!= sign(op)<br />

# => <strong>de</strong>sbordami<strong>en</strong>to<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 51


Claram<strong>en</strong>te la comprobación <strong><strong>de</strong>l</strong> <strong>de</strong>sbordami<strong>en</strong>to <strong>en</strong> el <strong>MIPS</strong> es realm<strong>en</strong>te compleja.<br />

Afortunadam<strong>en</strong>te <strong>en</strong> la mayoría <strong>de</strong> los casos no es necesario realizar dicha comprobación <strong>de</strong><br />

forma explícita. Por ejemplo <strong>en</strong> C no se ti<strong>en</strong><strong>en</strong> <strong>en</strong> cu<strong>en</strong>ta nunca los <strong>de</strong>sbordami<strong>en</strong>tos para<br />

obt<strong>en</strong>er programas más efici<strong>en</strong>tes, aun a costa <strong>de</strong> que se produzcan resultados erróneos. Otros<br />

l<strong>en</strong>guajes como Fortran o Ada si precisan que se <strong>de</strong>tect<strong>en</strong> los <strong>de</strong>sbordami<strong>en</strong>tos, pues <strong>en</strong> las<br />

aplicaciones escritas <strong>en</strong> dichos l<strong>en</strong>guajes prima mucho más la fiabilidad <strong>de</strong> los programas<br />

que su velocidad <strong>de</strong> ejecución. No obstante, <strong>en</strong> estos l<strong>en</strong>guajes se suele utilizar una rutina <strong>de</strong><br />

excepción para at<strong>en</strong><strong>de</strong>r las excepciones numéricas, por lo que la aproximación seguida por el<br />

<strong>MIPS</strong> es apropiada <strong>en</strong> estos casos.<br />

El programa mostrado <strong>en</strong> la transpar<strong>en</strong>cia se basa <strong>en</strong> verificar <strong>en</strong> primer lugar si los signos<br />

<strong>de</strong> los dos sumandos son distintos, <strong>en</strong> cuyo caso nunca se producirá un <strong>de</strong>sbordami<strong>en</strong>to.<br />

Para ello realiza una or exclusiva bit a bit <strong>de</strong> ambos sumandos con la instrucción <strong>MIPS</strong> xor.<br />

El bit <strong>de</strong> signo <strong><strong>de</strong>l</strong> resultado <strong>de</strong> la XOR será 1 si los signos <strong>de</strong> ambos sumandos son distintos<br />

y 0 si son iguales. Por tanto, si los signos son distintos, <strong>en</strong> t3 t<strong>en</strong>dremos un número negativo,<br />

por lo que mediante la instrucción <strong>de</strong> salto condicional se saltará a la etiqueta no<strong>de</strong>sb. Si ambos<br />

números ti<strong>en</strong><strong>en</strong> el mismo signo, se pue<strong>de</strong> producir un <strong>de</strong>sbordami<strong>en</strong>to, <strong>en</strong> cuyo caso el<br />

resultado t<strong>en</strong>drá distinto signo que los operandos. El resto <strong><strong>de</strong>l</strong> programa es similar al anterior,<br />

sólo que ahora se comprueba si los signos <strong><strong>de</strong>l</strong> resultado y <strong>de</strong> los sumandos son distintos, <strong>en</strong><br />

cuyo caso se salta a la etiqueta Desb para ejecutar el tratami<strong>en</strong>to <strong><strong>de</strong>l</strong> <strong>de</strong>sbordami<strong>en</strong>to.<br />

Como se ha com<strong>en</strong>tado antes, <strong>en</strong> las sumas sin signo no suele ser necesario comprobar<br />

el <strong>de</strong>sbordami<strong>en</strong>to. Por ello el <strong>MIPS</strong> no g<strong>en</strong>erará ninguna excepción <strong>en</strong> este caso. Si se necesita<br />

<strong>de</strong>tectar un <strong>de</strong>sbordami<strong>en</strong>to, la única manera es usando la secu<strong>en</strong>cia <strong>de</strong> instrucciones<br />

mostradas <strong>en</strong> la sigui<strong>en</strong>te transpar<strong>en</strong>cia.<br />

Aritmética. Suma y resta<br />

addu $t0, $t1, $t2 # suma sin <strong>de</strong>sbordami<strong>en</strong>to<br />

nor $t3, $t1, $zero # t3 = not(t1) =<br />

# C2(t1) - 1 = 2^32 -t1-1<br />

sltu $t3, $t3, $t2 # 2^32 -t1-1 < t2 =><br />

# 2^32 -1 < t1 + t2 =><br />

# <strong>de</strong>sbordami<strong>en</strong>to.<br />

bne $t3, $zero, Desb<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 52


En este caso el programa es más corto, aunque más difícil <strong>de</strong> <strong>en</strong>t<strong>en</strong><strong>de</strong>r.<br />

En primer lugar se inviert<strong>en</strong> todos los bits <strong>de</strong> t1. Para ello se utiliza la operación nor que<br />

calcula una OR negada bit a bit. Esta inversión es equival<strong>en</strong>te a calcular el complem<strong>en</strong>to a 2 -<br />

1 (recuer<strong>de</strong> que el complem<strong>en</strong>to a 2 se calcula invirti<strong>en</strong>do todos los bits y sumando 1). Como<br />

el complem<strong>en</strong>to a 2 <strong>de</strong> t1 es 2 32 -t1, el resultado <strong>de</strong> la operación anterior será 2 32 -t1-1. Si se<br />

compara este resultado con t2, t<strong>en</strong>emos que:<br />

(1)<br />

2 32 − t1 − 1 < t2 ⇔ 2 32 − 1 < t1 + t2<br />

Por tanto, si el resultado <strong>de</strong> la comparación es cierto, el resultado <strong>de</strong> t1+t2 será mayor <strong>de</strong><br />

2 32 − 1 y por tanto se necesitarán más <strong>de</strong> 32 bits para repres<strong>en</strong>tarlo. En consecu<strong>en</strong>cia, al no<br />

caber el resultado <strong>en</strong> 32 bits se habrá producido un <strong>de</strong>sbordami<strong>en</strong>to.<br />

Aritmética. Multiplicación<br />

El <strong>MIPS</strong> dispone <strong>de</strong> dos instrucciones para multiplicar:<br />

mult (con signo) o multu (sin signo).<br />

El resultado se almac<strong>en</strong>a <strong>en</strong> un registro <strong>de</strong> 64 bits,<br />

accesible <strong>en</strong> su mitad superior hi y <strong>en</strong> su mitad<br />

inferior lo mediante las instrucciones mfhi y mflo.<br />

Ej: mult $s0, $s1 multiplica s0 por s1<br />

Estas instrucciones no <strong>de</strong>tectan <strong>de</strong>sbordami<strong>en</strong>tos. El<br />

resultado cabrá <strong>en</strong> 32 bits si hi vale 0 <strong>en</strong> multu o la<br />

repetición <strong><strong>de</strong>l</strong> bit <strong>de</strong> signo <strong>en</strong> mult.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 53


En el caso <strong>de</strong> la multiplicación, el hardware es ligeram<strong>en</strong>te distinto según se multipliqu<strong>en</strong><br />

números con signo o números sin signo (<strong>de</strong> Miguel Anasagasti, 2000). Debido a esto, el<br />

<strong>MIPS</strong> dispone <strong>de</strong> dos instrucciones para multiplicar: mult para números con signo y multu<br />

para números sin signo. Ambas instrucciones multiplican el cont<strong>en</strong>ido <strong>de</strong> dos registros y almac<strong>en</strong>an<br />

el resultado <strong>en</strong> un registro <strong>de</strong> 64 bits. Como el producto <strong>de</strong> dos números <strong>de</strong> 32 bits<br />

nunca será mayor <strong>de</strong> 64 bits, no se producirá nunca ningún <strong>de</strong>sbordami<strong>en</strong>to, por lo que ambas<br />

instrucciones <strong>de</strong> multiplicación no g<strong>en</strong>eran excepciones.<br />

El registro <strong>de</strong> 64 bits <strong>en</strong> don<strong>de</strong> se almac<strong>en</strong>a el resultado es accesible <strong>en</strong> sus dos mita<strong>de</strong>s<br />

(hi y lo) mediante dos instrucciones especiales. La instrucción mfhi (<strong><strong>de</strong>l</strong> inglés move from<br />

high) traslada los 32 bits más significativos a un registro <strong>de</strong>stino. De la misma forma, mflo<br />

(<strong><strong>de</strong>l</strong> inglés move from low) traslada los 32 bits m<strong>en</strong>os significativos <strong><strong>de</strong>l</strong> resultado a un registro<br />

<strong>de</strong>stino. Por ejemplo, la instrucción mflo $s0 traslada los 32 bits m<strong>en</strong>os significativos <strong><strong>de</strong>l</strong><br />

resultado al registro s0.<br />

Cuando se está evaluando una expresión aritmética, interesa que todas las variables t<strong>en</strong>gan<br />

el mismo tamaño. Por tanto, <strong>de</strong>spués <strong>de</strong> realizar una multiplicación, interesa almac<strong>en</strong>ar<br />

el resultado <strong>en</strong> 32 bits <strong>en</strong> lugar <strong>de</strong> 64 para proseguir operando con el. Si se necesitan más<br />

<strong>de</strong> 32 bits para almac<strong>en</strong>ar el resultado, se habrá producido un “<strong>de</strong>sbordami<strong>en</strong>to <strong>de</strong> 32 bits”.<br />

El <strong>MIPS</strong> no ti<strong>en</strong>e ningún mecanismo hardware para <strong>de</strong>tectarlo, si<strong>en</strong>do responsabilidad <strong><strong>de</strong>l</strong><br />

programador su <strong>de</strong>tección. En el caso <strong>de</strong> multiplicaciones sin signo basta con comprobar que<br />

el registro hi esté a cero. En el caso <strong>de</strong> números con signo, el registro hi ha <strong>de</strong> ser todo ceros<br />

si lo es positivo o todo unos si lo es negativo.<br />

Ejercicio<br />

Escriba la secu<strong>en</strong>cia <strong>de</strong> instrucciones para multiplicar sin signo s0 por s1 y almac<strong>en</strong>ar<br />

el resultado <strong>en</strong> s2. Si se produce un <strong>de</strong>sbordami<strong>en</strong>to <strong>de</strong> 32 bits se pondrá t0 a uno y si no se<br />

<strong>de</strong>jará a cero. Repita el ejercicio para números con signo.<br />

Aritmética. División<br />

El <strong>MIPS</strong> dispone <strong>de</strong> dos instrucciones para dividir:<br />

div (con signo) o divu (sin signo).<br />

El coci<strong>en</strong>te se almac<strong>en</strong>a <strong>en</strong> lo y el resto <strong>en</strong> hi.<br />

Ej: div $s0, $s1 divi<strong>de</strong> s0 <strong>en</strong>tre s1<br />

Estas instrucciones no <strong>de</strong>tectan división por cero.<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 54


Al igual que <strong>en</strong> la multiplicación, son necesarias dos instrucciones para la división: div<br />

para números con signo y divu para números sin signo. En ambos casos el resultado se<br />

almac<strong>en</strong>a <strong>en</strong> el mismo registro <strong>de</strong> 64 bits utilizado para la multiplicación. En la parte alta<br />

(hi) se almac<strong>en</strong>a el resto y <strong>en</strong> la parte baja (lo) se almac<strong>en</strong>a el coci<strong>en</strong>te.<br />

Convi<strong>en</strong>e <strong>de</strong>stacar que el <strong>MIPS</strong> no <strong>de</strong>tecta la división por cero. A<strong>de</strong>más el resultado obt<strong>en</strong>ido<br />

<strong>en</strong> este caso es inpre<strong>de</strong>cible. Por tanto es tarea <strong><strong>de</strong>l</strong> programador el evitar las divisiones<br />

por cero para evitar sorpresas <strong>de</strong>sagradables.<br />

Ejercicio<br />

Escriba una secu<strong>en</strong>cia <strong>de</strong> instrucciones para dividir s0 <strong>en</strong>tre s1 y almac<strong>en</strong>ar el coci<strong>en</strong>te<br />

<strong>en</strong> el registro s2 y el resto <strong>en</strong> el registro s3. Si el divisor vale cero no se realizará la división<br />

y se pondrá a uno el registro t0. En caso contrario, <strong>de</strong>spués <strong>de</strong> realizar la división se <strong>de</strong>jará<br />

t0 a cero. Los números almac<strong>en</strong>ados <strong>en</strong> s0 y s1 son números con signo.<br />

Aritmética. Ej: (a0+a1)*a2/a3<br />

1 func: beq $a3, $zero, Error<br />

2 add $t0, $a0, $a1<br />

3 mult $t0, $a2<br />

4 mflo $t0<br />

5 mfhi $t1<br />

6 slt $t2, $t0, $zero #res0<br />

9 j L1<br />

10 Nega: sltiu $t2, $t1, -1 # -1=0xffff<br />

11 bne $t2, $zero, Error<br />

12 L1: div $t0, $a3<br />

13 mflo $v0<br />

14 add $v1, $zero, $zero<br />

15 jr $ra<br />

16 Error: addi $v1, $zero, 1<br />

17 jr $ra<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 55


En la transpar<strong>en</strong>cia se muestra el código para implem<strong>en</strong>tar una función que calcule la<br />

expresión (a0+a1)*a2/a3 (variables con signo). El resultado se <strong>de</strong>volverá <strong>en</strong> v0 y <strong>en</strong> v1 se<br />

<strong>de</strong>volverá un 0 si no se ha producido ningún error <strong>en</strong> el cálculo <strong>de</strong> la expresión o un 1 si se<br />

produce <strong>de</strong>sbordami<strong>en</strong>to <strong>en</strong> la multiplicación o una división por cero.<br />

En primer lugar se comprueba que a3 no sea cero. Si lo es, se salta al final <strong>de</strong> la función,<br />

<strong>de</strong>s<strong>de</strong> don<strong>de</strong> se pone v1 a 1 para indicar el error y se retorna <strong>de</strong> la función.<br />

Si a3 no es cero, se comi<strong>en</strong>za a evaluar la expresión. En primer lugar se realiza la suma.<br />

Si ocurriese un <strong>de</strong>sbordami<strong>en</strong>to se produciría una excepción, <strong>de</strong>s<strong>de</strong> don<strong>de</strong> se podría tratar el<br />

error. Como aún no se han estudiado las excepciones, se <strong>de</strong>ja la implem<strong>en</strong>tación <strong>de</strong> la rutina<br />

<strong>de</strong> at<strong>en</strong>ción a la excepción para más a<strong><strong>de</strong>l</strong>ante. A continuación se realiza la multiplicación,<br />

<strong>de</strong>jando el resultado <strong>en</strong> los registros t0 y t1. Como se pret<strong>en</strong><strong>de</strong> continuar la evaluación <strong>de</strong><br />

la expresión usando números <strong>de</strong> 32 bits, el resultado ha <strong>de</strong> po<strong>de</strong>rse almac<strong>en</strong>ar <strong>en</strong> t0, por lo<br />

que t1 t<strong>en</strong>drá que valer 0 si el resultado es positivo o 0xffffffff si el resultado es negativo.<br />

Esta comprobación se realiza <strong>en</strong> las instrucciones 6 a 11. En la instrucción 6 se comprueba el<br />

signo <strong><strong>de</strong>l</strong> resultado. Si es positivo se ejecutará la instrucción 8 que saltará a la etiqueta Error<br />

si t1 no vale cero. Si el resultado es negativo, <strong>en</strong> la instrucción 10 se comprueba si t1 vale<br />

0xffffffff. Como las instrucciones <strong>de</strong> comparación exti<strong>en</strong>d<strong>en</strong> el signo <strong>de</strong> la constante <strong>de</strong> 16<br />

bits, comparar con -1 es comparar con 0xffffffff. Como la comparación se realiza sin signo,<br />

si t1 es distinto <strong>de</strong> 0xffffffff se producirá el salto <strong>en</strong> la instrucción 11 para ir a la etiqueta<br />

Error.<br />

Si no hay <strong>de</strong>sbordami<strong>en</strong>to <strong>en</strong> la multiplicación, se proce<strong>de</strong> a realizar la división y a<br />

<strong>de</strong>volver el control a “qui<strong>en</strong>” ha llamado a la función, aunque previam<strong>en</strong>te se <strong>de</strong>posita el<br />

resultado <strong>en</strong> v0 y un 0 <strong>en</strong> v1 para indicar que la evaluación <strong>de</strong> la expresión se ha realizado<br />

con éxito.<br />

Ejercicio<br />

Modifique la función anterior para comprobar explícitam<strong>en</strong>te el <strong>de</strong>sbordami<strong>en</strong>to <strong>de</strong> la<br />

suma utilizando el algoritmo mostrado <strong>en</strong> la página 51<br />

55-2


Aritmética y lógica<br />

Aparte <strong>de</strong> la +,-,* y /, el <strong>MIPS</strong> dispone <strong>de</strong> una serie <strong>de</strong><br />

operaciones lógicas y aritméticas adicionales:<br />

• and <strong>de</strong>st, orig1, orig2<br />

• andi <strong>de</strong>st, orig1, const<br />

• or <strong>de</strong>st, orig1, orig2<br />

• ori <strong>de</strong>st, orig1, const<br />

• xor <strong>de</strong>st, orig1, orig2<br />

• xori <strong>de</strong>st, orig1, const<br />

• nor <strong>de</strong>st, orig1, orig2<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 56<br />

Aparte <strong>de</strong> las operaciones aritméticas estudiadas hasta ahora, <strong>en</strong> muchos programas es<br />

necesario realizar operaciones lógicas a nivel <strong>de</strong> bit.<br />

El <strong>MIPS</strong> incluye las instrucciones lógicas mostradas <strong>en</strong> la transpar<strong>en</strong>cia. Todas ellas<br />

realizan una operación lógica bit a bit <strong>en</strong>tre los dos registros orig<strong>en</strong> y <strong>de</strong>positan su resultado<br />

<strong>en</strong> el registro <strong>de</strong>stino. Se incluy<strong>en</strong> las dos operaciones lógicas fundam<strong>en</strong>tales, AND y OR, así<br />

como la XOR. Se incluye a<strong>de</strong>más la operación NOR, que realiza la misma operación que una<br />

OR salvo que se niega el resultado. Esta instrucción permite realizar la operación fundam<strong>en</strong>tal<br />

NOT. ¿Cómo<br />

Las operaciones AND, OR y XOR dispon<strong>en</strong> <strong>de</strong> versiones <strong>en</strong> las cuales el segundo operando<br />

es una constante <strong>de</strong> 16 bits. Como el registro con el que se opera es <strong>de</strong> 32 bits, los<br />

16 bits superiores <strong>de</strong> la constante se pon<strong>en</strong> a 0 antes <strong>de</strong> realizar la operación lógica. Recuer<strong>de</strong><br />

que este comportami<strong>en</strong>to es distinto <strong><strong>de</strong>l</strong> ofrecido <strong>en</strong> las constantes <strong>de</strong> las operaciones <strong>de</strong><br />

suma, resta y comparación, <strong>en</strong> las cuales se exti<strong>en</strong><strong>de</strong> el signo.


Aritmética y lógica<br />

Por último, el <strong>MIPS</strong> dispone <strong>de</strong> una serie <strong>de</strong><br />

instrucciones <strong>de</strong> <strong>de</strong>splazami<strong>en</strong>to <strong>de</strong> bits.<br />

• Despl. lógico a izq.: sll rd, ro, <strong>de</strong>sp<br />

• Despl. lógico a izq. var.: sllv rd, ro, r<strong>de</strong>s<br />

• Despl. lógico a <strong>de</strong>r.: srl rd, ro, <strong>de</strong>sp<br />

• Despl. lógico a <strong>de</strong>r. var.: srlv rd, ro, r<strong>de</strong>s<br />

• Despl. aritmético a <strong>de</strong>r.: sra rd, ro, <strong>de</strong>sp<br />

• Despl. arit. a <strong>de</strong>r. var.: srav rd, ro, r<strong>de</strong>s<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 57<br />

El <strong>MIPS</strong> dispone <strong>de</strong> varias instrucciones <strong>de</strong> <strong>de</strong>splazami<strong>en</strong>to <strong>de</strong> bits. Estas instrucciones<br />

pued<strong>en</strong> <strong>de</strong>splazar un registro orig<strong>en</strong> el número <strong>de</strong> bits especificado <strong>en</strong> la constante <strong>de</strong>sp o <strong>en</strong><br />

el registro r<strong>de</strong>s para los <strong>de</strong>splazami<strong>en</strong>tos variables. El resultado se almac<strong>en</strong>a <strong>en</strong> el registro<br />

<strong>de</strong>stino.<br />

Cuando se <strong>de</strong>splaza a la izquierda se rell<strong>en</strong>an los bits vacantes con ceros. Por ejemplo<br />

si se <strong>de</strong>splaza 01000111 a la izquierda tres posiciones, el resultado será 00111000.<br />

1 En cambio,<br />

cuando se <strong>de</strong>splaza a la <strong>de</strong>recha cab<strong>en</strong> dos posibilida<strong>de</strong>s: rell<strong>en</strong>ar con ceros (<strong>de</strong>splazami<strong>en</strong>to<br />

lógico) o rell<strong>en</strong>ar con el bit <strong>de</strong> signo (<strong>de</strong>splazami<strong>en</strong>to aritmético). Por ejemplo, si se <strong>de</strong>sea<br />

<strong>de</strong>splazar el valor 10010011 dos bits a la <strong>de</strong>recha, si se realiza un <strong>de</strong>splazami<strong>en</strong>to lógico, el<br />

resultado será 00100100, pero si se realiza un <strong>de</strong>splazami<strong>en</strong>to aritmético, el resultado será<br />

11100100.<br />

Las instrucciones <strong>de</strong> <strong>de</strong>splazami<strong>en</strong>to ti<strong>en</strong><strong>en</strong> dos usos fundam<strong>en</strong>tales. Los <strong>de</strong>splazami<strong>en</strong>tos<br />

lógicos se usan para manipular bits. Por ejemplo si se <strong>de</strong>sean extraer los 16 bits más<br />

significativos <strong>de</strong> un registro <strong>de</strong> 32 bits (s0) y almac<strong>en</strong>arlos <strong>en</strong> s1 se pue<strong>de</strong> ejecutar la instrucción<br />

srl $s1, $s0, 16. En este tipo <strong>de</strong> operaciones no es necesario ext<strong>en</strong><strong>de</strong>r el bit <strong>de</strong><br />

signo, por lo que se usan las instrucciones <strong>de</strong> <strong>de</strong>splazami<strong>en</strong>to lógico.<br />

El otro uso <strong>de</strong> las instrucciones <strong>de</strong> <strong>de</strong>splazami<strong>en</strong>to es para realizar multiplicaciones y<br />

divisiones por pot<strong>en</strong>cias <strong>de</strong> dos. Cada bit que se <strong>de</strong>splaza un número binario a la izquierda es<br />

equival<strong>en</strong>te a multiplicar por 2. De la misma forma, cada bit que se <strong>de</strong>splaza a la <strong>de</strong>recha es<br />

equival<strong>en</strong>te a dividir por 2, aunque <strong>en</strong> este caso si el número es negativo es necesario introducir<br />

unos por la izquierda para que se mant<strong>en</strong>ga el signo. Por tanto, cuando se <strong>de</strong>see <strong>de</strong>splazar<br />

1 Se han usado <strong>en</strong> el ejemplo números <strong>de</strong> 8 bits para simplificar. El <strong>MIPS</strong> <strong>de</strong>splaza siempre<br />

valores <strong>de</strong> 32 bits.


a la <strong>de</strong>recha para dividir por pot<strong>en</strong>cias <strong>de</strong> dos, será necesario utilizar <strong>de</strong>splazami<strong>en</strong>tos aritméticos.<br />

Convi<strong>en</strong>e resaltar que <strong>en</strong> estas operaciones el <strong>MIPS</strong> no comprueba si se produc<strong>en</strong><br />

<strong>de</strong>sbordami<strong>en</strong>tos.<br />

57-2<br />

Aritmética y lógica. Ejemplo<br />

int a, V[100], i, j, k;<br />

while(V[i] == k){<br />

i = i + j;<br />

}<br />

Se traduce <strong>en</strong> (a-k se asignan a los registros s0-s4):<br />

Bucle: sll $t1, $s2, 2 # t1 = 4i<br />

add $t1, $t1, $s1 # t1 = dir. <strong>de</strong> V[i]<br />

lw $t0, 0($t1) # t0 = V[i]<br />

bne $t0, $s4, Fin # si i!=k salta<br />

add $s2, $s2, $s3 # i = i + j<br />

j Bucle<br />

Fin:<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 58


El código C mostrado <strong>en</strong> la transpar<strong>en</strong>cia es el mismo que se utilizó <strong>en</strong> la página 25. Al<br />

igual que antes, es necesario multiplicar por 4 el índice <strong><strong>de</strong>l</strong> vector para acce<strong>de</strong>r a cada uno <strong>de</strong><br />

los elem<strong>en</strong>tos. En el programa <strong>en</strong> <strong>en</strong>samblador <strong>de</strong> la página 25 se utilizaron dos instrucciones<br />

<strong>de</strong> suma para realizar dicha multiplicación. Otra alternativa sería usar una instrucción <strong>de</strong><br />

multiplicación, aunque <strong>en</strong> este caso se necesitarían tres instrucciones:<br />

addi $t0, $zero, 4<br />

multu $s2, $t0<br />

mflo $t0<br />

Obviam<strong>en</strong>te no es la solución más apropiada. No obstante, si se ti<strong>en</strong>e <strong>en</strong> cu<strong>en</strong>ta que 4 es<br />

una pot<strong>en</strong>cia <strong>de</strong> 2, po<strong>de</strong>mos realizar la multiplicación por 4 mediante <strong>de</strong>splazami<strong>en</strong>tos. Como<br />

4 = 2 2 , para multiplicar por 4 basta con <strong>de</strong>splazar 2 bits a la izquierda, que es lo que se ha<br />

hecho <strong>en</strong> la primera instrucción <strong><strong>de</strong>l</strong> programa <strong>en</strong> <strong>en</strong>samblador.<br />

Ejercicio<br />

En muchas ocasiones es más efici<strong>en</strong>te implantar una multiplicación por una constante<br />

como una serie <strong>de</strong> <strong>de</strong>splazami<strong>en</strong>tos y sumas. Escriba una secu<strong>en</strong>cia <strong>de</strong> instrucciones <strong>en</strong><br />

<strong>en</strong>samblador que multipliqu<strong>en</strong> el registro s0 por 5 y <strong>de</strong>posit<strong>en</strong> el resultado <strong>en</strong> t0.<br />

Carga <strong>de</strong> constantes<br />

Hasta ahora se ha visto cómo cargar una constante<br />

<strong>de</strong> 16 bits <strong>en</strong> un registro.<br />

Para cargar un valor <strong>de</strong> 32 bits (p. ej. 0x12345678)<br />

son necesarias dos instrucciones:<br />

lui $s0, 0x1234<br />

ori $s0, $s0, 0x5678<br />

La pseudoinstrucción li hace el mismo trabajo:<br />

li<br />

$s0, 0x12345678<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 59


Aunque la mayoría <strong>de</strong> las constantes usadas <strong>en</strong> los programas son m<strong>en</strong>ores <strong>de</strong> 16 bits,<br />

<strong>en</strong> ciertas ocasiones es necesario usar constantes <strong>de</strong> 32 bits. Para ello, el <strong>MIPS</strong> dispone <strong>de</strong><br />

una instrucción <strong>de</strong> carga especial que toma una constante <strong>de</strong> 16 bits y la sitúa <strong>en</strong> los 16 bits<br />

más significativos <strong><strong>de</strong>l</strong> registro <strong>de</strong>stino, <strong>de</strong>jando los 16 bits m<strong>en</strong>os significativos a cero. Dicha<br />

instrucción se d<strong>en</strong>omina lui (<strong><strong>de</strong>l</strong> inglés load upper inmediate). Para cargar los bits m<strong>en</strong>os<br />

significativos <strong><strong>de</strong>l</strong> registro se usa la instrucción ori, que realiza una OR bit a bit <strong><strong>de</strong>l</strong> registro<br />

<strong>de</strong>stino con una constante <strong>de</strong> 16 bits ext<strong>en</strong>dida con ceros <strong>en</strong> su parte superior. Así, <strong>en</strong> el<br />

ejemplo <strong>de</strong> la transpar<strong>en</strong>cia se realizará una OR <strong>en</strong>tre:<br />

0x12340000<br />

0x00005678<br />

Cuyo resultado es 0x12345678.<br />

Como el l<strong>en</strong>guaje nativo <strong><strong>de</strong>l</strong> <strong>MIPS</strong> es un poco limitado, dada su naturaleza RISC, los <strong>en</strong>sambladores<br />

<strong><strong>de</strong>l</strong> <strong>MIPS</strong> dispon<strong>en</strong> <strong>de</strong> una serie <strong>de</strong> pseudoinstrucciones para facilitarle la vida<br />

a los programadores. Dichas pseudoinstrucciones no son más que una especie <strong>de</strong> “abreviaturas”<br />

<strong>de</strong> varias instrucciones <strong><strong>de</strong>l</strong> <strong>MIPS</strong>. Una pseudoinstrucción muy útil es la li (<strong>de</strong> load<br />

inmediate), que carga una constante, in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>tem<strong>en</strong>te <strong>de</strong> su tamaño, <strong>en</strong> un registro. Cuando<br />

el <strong>en</strong>samblador <strong>en</strong>cu<strong>en</strong>tra esta pseudoinstrucción evalúa el tamaño <strong>de</strong> la constante y si ésta<br />

es m<strong>en</strong>or <strong>de</strong> 16 bits g<strong>en</strong>era la instrucción ori rd, const. Si la constante es mayor <strong>de</strong> 16<br />

bits, <strong>en</strong>tonces g<strong>en</strong>era la combinación lui+ori vista <strong>en</strong> la transpar<strong>en</strong>cia.<br />

Ejercicio<br />

Utilizando el simulador SPIM, indique cual es la traducción a instrucciones <strong>MIPS</strong> <strong>de</strong> la<br />

pseudoinstrucción li para las sigui<strong>en</strong>tes constantes: 1, -1 y 0x10007. ¿Se realiza siempre la<br />

traducción óptima<br />

Para saber más<br />

En este tema sólo se han mostrado algunas <strong>de</strong> las<br />

instrucciones disponibles <strong>en</strong> el <strong>MIPS</strong>.<br />

Un listado completo se <strong>en</strong>cu<strong>en</strong>tra <strong>en</strong> el apéndice A <strong>de</strong><br />

(Patterson y H<strong>en</strong>nessy, 2000), disponible on-line <strong>en</strong> la<br />

página <strong><strong>de</strong>l</strong> SPIM.<br />

Los manuales completos <strong>de</strong> la arquitectura <strong>MIPS</strong><br />

(<strong>MIPS</strong> Technologies, 2002) se <strong>en</strong>cu<strong>en</strong>tran también<br />

disponibles on-line <strong>en</strong> la página <strong>de</strong> <strong>MIPS</strong><br />

Technologies (accesible <strong>de</strong>s<strong>de</strong> la página web <strong>de</strong> la<br />

asignatura).<br />

ICAI<strong>de</strong>a<br />

Estructura <strong>de</strong> Computadores Capítulo 3b: <strong>Programación</strong> <strong>en</strong> <strong>en</strong>samblador <strong><strong>de</strong>l</strong> <strong>MIPS</strong>.– p. 60


Refer<strong>en</strong>cias<br />

<strong>de</strong> Miguel Anasagasti, P. (2000). Fundam<strong>en</strong>tos <strong>de</strong> los computadores. Paraninfo-Thomson<br />

learning.<br />

<strong>MIPS</strong> Technologies (2002). <strong>MIPS</strong>32 TM Architecture For Programmers. <strong>MIPS</strong> Technologies,<br />

Mountain View, CA, 1 edition.<br />

Patterson, D. A. y H<strong>en</strong>nessy, J. L. (2000). Estructura y diseño <strong>de</strong> computadores. Interficie<br />

circuitería/programación. Reverté.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!