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

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

dea.icai.upcomillas.es
from dea.icai.upcomillas.es More from this publisher
28.01.2015 Views

Estructura de Computadores Capítulo 3b: Programación en ensamblador del MIPS. José Daniel Muñoz Frías Universidad Pontificia Comillas. ETSI ICAI. Departamento de Electrónica y Automática ICAIdea Estructura de Computadores Capítulo 3b: Programación en ensamblador del MIPS.– p. 1 Índice 1. Introducción. 2. Registros disponibles. 3. Operaciones aritméticas. 4. Acceso a memoria. 5. Codificación en lenguaje máquina. 6. Toma de decisiones. 7. Llamadas a funciones. 8. Manejo de caracteres. 9. Aritmética. ICAIdea Estructura de Computadores Capítulo 3b: Programación en ensamblador del MIPS.– p. 2

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!