Está en la página 1de 4

Conceptos básicos del Lenguaje Ensamblador MIPS

Tipos de instrucciones
En lenguaje ensamblador hay tres tipos de instrucciones:

Las Instrucciones máquina, que son las que vienen en la tabla de instrucciones y se traducen casi
literalmente a código máquina.
Los Directivos, que son órdenes dadas al compilador y se caracterizan porque comienzan con un punto.
Las Pseudoinstrucciones o instrucciones sintéticas, que son instrucciones similares a las instrucciones
máquina pero que no están en la tabla de instrucciones. Es el compilador el que las traduce por una o más
instrucciones máquina. Se utilizan para que el código sea más legible.
Ejemplo: move rd, rs se traduce como add rd, rs, $zero

En un programa también se pueden poner comentarios, que son ignorados por el compilador y se ponen
para facilitar la legibilidad del programa. En ensamblador de MIPS los comentarios comienzan con #, de forma
que lo que esté entre ese símbolo y el final de la línea (que es el separador de instrucción) se ignora.
Cualquier instrucción puede ir precedida de una etiqueta que es un identificador seguido de dos puntos (:)
Cada etiqueta representa la dirección de la instrucción o dato que le siga. Los identificadores son una
secuencia de caracteres alfanuméricos que no comiencen por un número. Los códigos de las operaciones son
palabras reservadas que no pueden utilizarse como identificadores.
Los números se interpretan en decimal. Para que se interpreten en hexadecimal se pone el prefijo 0x.

Estructura de un programa en lenguaje ensamblador


Un programa tiene dos áreas bien diferenciadas: el área de datos, donde se reserva el espacio en memoria para
las variables que lo necesiten, y el área de código donde están las instrucciones ejecutables.

El área de datos se identifica por comenzar con el directivo .data. A partir de ese punto se puede reservar
espacio para las variables del programa mediante los directivos siguientes:
• .byte: Reserva espacio y lo inicializa con los valores que vienen a continuación, cada uno como
un entero en un byte.
• .half: Reserva espacio y lo inicializa con los valores que vienen a continuación, cada uno como
un entero en 16 bits.
• .word: Reserva espacio y lo inicializa con los valores que vienen a continuación, cada uno como
un entero en 32 bits.
• .space: Reserva el número de bytes que siguen y los inicializa a 0.
• .ascii "Cadena": Reserva espacio en memoria para la cadena de caracteres especificada, pero
no escribe un terminador de carácter nulo al final. Si se quieren incluir en la cadena caracteres
especiales seguiremos las mismas convenciones que en el lenguaje C (\n es el fin de línea, \t es el
tabulador, \" son las comillas, etc.)
• .asciiz "Cadena": Hace lo mismo, con carácter terminador nulo al final.
• .float: Reserva espacio y lo inicializa con los valores que siguen, cada uno como números en
representación de punto flotante de simple precisión.
• .double: Lo mismo que el anterior pero en doble precisión.
El área de código se caracteriza por comenzar con el directivo .text, después ya se puede poner la
primera instrucción del programa que debe tener la etiqueta main, eso indica que es la dirección a la que
se transfiere el control. Para finalizar la ejecución de un programa hay que poner las instrucciones:
li $v0 10 finalizar la ejecución del programa ordenadamente
syscall
que devuelven el control al sistema operativo.
2

Instrucciones MIPS32 utilizadas


(En negro, las que se comentan en las transparencias; en azul, otras que son útiles pero que no se comentan en
las transparencias; en verde, las pseudoinstrucciones)

1. Instrucciones de movimiento de datos


lw rt, d(rs) Carga 32 bits en rt desde la dirección d + rs
lw rt, (rs) Carga 32 bits en rt desde la dirección especificada en rs
lh rt, d(rs) Carga 16 bits en rt desde la dirección d + rs extendiendo signo
lh rt, (rs) Carga 16 bits en rt desde la dirección especificada en rs extendiendo signo
lhu rt, d(rs) Carga 16 bits en rt desde la dirección d + rs sin extender signo rellenando con 0’s
lhu rt, (rs) Carga 16 bits en rt desde la dirección dada en rs sin extender signo rellenando con 0’s
lb rt, d(rs) Carga 8 bits en rt desde la dirección d + rs extendiendo signo
lb rt, (rs) Carga 8 bits en rt desde la dirección especificada en rs extendiendo signo
lbu rt, d(rs) Carga 8 bits en rt desde la dirección d + rs sin extender signo rellenando con 0’s
lbu rt, (rs) Carga 8 bits en rt desde la dirección dada en rs sin extender signo rellenando con 0’s
sw rt, d(rs) Almacena rt en la dirección d + rs
sw rt, (rs) Almacena rt en la dirección especificada en rs
sh rt, d(rs) Almacena los 16 bits más bajos de rt en la dirección d + rs
sh rt, (rs) Almacena los 16 bits más bajos de rt en la dirección especificada en rs
sb rt, d(rs) Almacena los 8 bits más bajos de rt en la dirección d + rs
sb rt, (rs) Almacena los 8 bits más bajos de rt en la dirección especificada en rs
mfhi rd Copia el contenido del registro HI en rd
mflo rd Copia el contenido del registro LO en rd
move rd, rs Copia el contenido de rs en rd (add rd, rs, $zero)
lui rd, Inm Copia el valor Inm de 16 bits en la mitad más alta de rd
la rd, Etiqueta Carga la dirección representada por Etiqueta en el registro rd
li rd, Inm Carga el valor Inm (de cualquier tamaño) en rd

2. Instrucciones de aritmética entera


add rd, rs, rt Suma con detección de desbordamiento: rd ← rs + rt
addi rt, rs, Inm Suma inmediata: rt ← rs + Inm (con signo extendido)
addu rd, rs, rt Suma sin detección de desbordamiento: rd ← rs + rt
addiu rt, rs, Inm Suma inmediata sin detección de desbord.: rt ← rs + Inm (signo extendido)
sub rd, rs, rt Resta con detección de desbordamiento: rd ← rs − rt
subu rd, rs, rt Resta sin detección de desbordamiento: rd ← rs − rt
mult rs, rt Multiplicación con signo: HI:LO ← rs × rt
multu rs, rt Multiplicación sin signo: HI:LO ← rs × rt
mul rd, rs, rt Multiplicación: rd ← 32 bits más bajos de rs × rt (extendiendo signo)
mulu rd, rs, rt Multiplicación: rd ← 32 bits más bajos de rs × rt (sin extender signo)
div rs, rt División con signo: rs/rt: HI ← resto; LO ← cociente
divu rs, rt División sin signo: rs/rt: HI ← resto; LO ← cociente

3. Instrucciones lógicas
and rd, rs, rt rd ← rs ∧ rt, bit a bit
andi rt, rs, Inm rt ← rs ∧ Inm (inmediato de 16 bits sin extensión de signo)
or rd, rs, rt rd ← rs ∨ rt, bit a bit
ori rt, rs, Inm rt ← rs ∨ Inm (inmediato de 16 bits sin extensión de signo)
xor rd, rs, rt rd ← rs ⊕ rt
xori rt, rs, Inm rt ← rs ⊕ Inm (inmediato de 16 bits sin extensión de signo)
nor rd, rs, rt rd ←!(rs ∨ rt)

4. Instrucciones de desplazamiento
sll rd, rt, shamt rd ← rt << shamt
srl rd, rt, shamt rd ← rt >> shamt
3

5. Instrucciones set condicional


slt rd, rs, rt Si (rs < rt) rd ← 1 si no rt ← 0 (comparación con signo)
slti rt, rs, Inm Si (rs < Inm) rd ← 1 si no rt ← 0 (comparación con signo extendido)
sltu rd, rs, rt Si (rs < rt) rd ← 1 si no rt ← 0 (comparación sin signo)
sltui rt, rs, Inm Si (rs < Inm) rd ← 1 si no rt ← 0 (comparación sin signo)

6. Instrucciones de salto
beq rs, rt, Etiqueta Si (rs == rt) continúa la ejecución en la instrucción situada en Etiqueta
si no, continúa en la instrucción siguiente
bne rs, rt, Etiqueta Si (rs ! = rt) continúa la ejecución en la instrucción situada en Etiqueta
si no continúa en la instrucción siguiente
blt rs, rt, Etiqueta Si (rs < rt) continúa la ejecución en la instrucción situada en Etiqueta
si no, continúa en la instrucción siguiente
b Etiqueta Salta incondicionalmente a Etiqueta (direccionamiento relativo)
j Etiqueta Salta incondicionalmente a Etiqueta (direccionamiento pseudoabsoluto)
jal Etiqueta Salta incondicionamente a Etiqueta y
$ra ← Dirección de la siguiente instrucción
jr rs Salta incondicionamente a la dirección contenida en el registro rs

7. Instrucciones de punto flotante

a) Aritméticas
add.s f d, f s, f t f d ← f s + f t (simple precisión)
sub.s f d, f s, f t f d ← f s − f t (simple precisión)
mul.s f d, f s, f t f d ← f s × f t (simple precisiónn)
div.s f d, f s, f t f d ← f s/f t (simple precisión)
neg.s f d, f s f d ← −f s (simple precisión)
abs.s f d, f s fd ← √|f s| (simple precisión)
sqrt.s f d, f s f d ← f s (simple precisión)
trunc.w.s f d, f s f d ← Truncamiento a entero del valor almacenado en f s
add.d f d, f s, f t f d ← f s + f t (doble precisión)
sub.d f d, f s, f t f d ← f s − f t (doble precisión)
mul.d f d, f s, f t f d ← f s × f t (doble precisión)
div.d f d, f s, f t f d ← f s/f t (doble precisión)
neg.d f d, f s f d ← −f s (doble precisión)
abs.d f d, f s fd ← √|f s| (doble precisión)
sqrt.d f d, f s f d ← f s (doble precisión)
trunc.w.d f d, f s f d ← Truncamiento a entero del valor almacenado en el par de registros
fs : fs + 1
b) De movimiento de datos
mov.s f d, f s fd ← fs
mov.d f d, f s fd : fd + 1 ← fs : fs + 1
mfc1 rd, f s rd ← f s
mfc1.d rd, f s rd : rd + 1 ← f s : f s + 1
mtc1 rd, f s f s ← rd
c) De acceso a memoria
lwc1 f d, d(rs) Carga 32 bits en el registro FP f d desde la dirección d + rs
lwc1 f d, (rs) Carga 32 bits en el registro FP f d desde la dirección especificada en rs
swc1 f d, d(rs) Almacena en la dirección d + rs los 32 bits del registro FP f d
swc1 f d, (rs) Almacena en la dirección especificada en rs los 32 bits del registro FP f d
ldc1 f d, d(rs) Carga 64 bits en los registros FP f d : f d + 1 desde la dirección d + rs
ldc1 f d, (rs) Carga 64 bits en los registros FP f d : f d + 1 desde la dirección dada en rs
sdc1 f d, d(rs) Almacena en la dirección d + rs los 64 bits de los registros FP f d : f d + 1
sdc1 f d, (rs) Almacena en dirección dada en rs los 64 bits de los registros FP f d : f d + 1
4

d) De conversión de datos
cvt.d.s f d, f s Convierte el valor FP 32 de f s a FP 64 y lo deja en f d : f d + 1
cvt.d.w f d, f s Convierte el valor entero de 32 bits de f s a FP 64 en f d : f d + 1
cvt.s.d f d, f s Convierte FP 64 de f s : f s + 1 a FP 32 en f d
cvt.s.w f d, f s Convierte entero 32 de f s a FP 32 en f d
cvt.w.d f d, f s Convierte de FP 64 de f s : f s + 1 a entero 32 en f d
cvt.w.s f d, f s Convierte de FP 32 de f s a entero 32 en f d
e) Instrucciones set condicional
c.**.s cc f s, f t Compara los registros FP de 32 bits y pone a 1 la bandera de condición cc
si se cumple la condición, y si no se cumple, la pone en 0. ** puede ser:
"le"(menor o igual), "eq"(igual), "lt"(menor que).
Si no se especifica cc se supone que es la bandera de condición 0.
c.**.d cc f s, f t Análoga a la anterior en doble precisión
f ) Bifurcación condicional
bc1t cc Etiqueta Salta a Etiqueta si la bandera de condición de punto flotante cc es 1.
Si no se especifica cc se supone que es la bandera de condición 0.
bc1fcc Etiqueta salta a Etiqueta si la bandera de condición de punto flotante cc es 0.
Si no se especifica cc se supone que es la bandera de condición 0.

Registros utilizados
$s0-$s7: Para almacenar valores de variables de código de alto nivel. no se pueden modificar por funciones
$t0-$t9: Como almacenamiento temporal para cálculos intermedios.
$a0-$a3: Para pasa argumentos a un procedimiento.
$v0-$v1: Para devolver resultados de un procedimiento.
$0 o $zero: Todo ceros siempre. Sólo se lee sobre él.
$sp: Stack pointer, puntero de cima de pila.
$ra: Registro donde se almacena la dirección retorno después de una llamada de procedimiento.
$fp: Frame pointer, registro en el que se almacena la dirección en la que comienza la "trama de
procedimiento"o "registro de activación", que es la zona de la pila donde se almacenan inicial-
mente las variables locales del procedimiento que no van a registros, arrays, direcciones de
retorno almacenadas, etc. Los accesos a esas posiciones se hacen relativos al valor del registro
$fp, en el cual se almacena el valor de $sp antes de poner en la pila todas esas informaciones.
$gp: Global pointer, contiene una dirección centrada en la zona donde se almacenan las variables
estáticas para poderlas referenciar fácilmente.

Llamadas al sistema
El sistema proporciona diversas funciones a través de la instrucción syscall. Para solicitar un servicio, el
programa carga el código de la llamada en el registro $v0 y los argumentos en los registros $a0-$a3 ($f12
para valores de punto flotante). Las llamadas de sistema que devuelven resultado lo dejan en el registro $v0
($f0 para los resultados de punto flotante). A continuación se resumen las principales de estas llamadas de
sistema:
Servicio Código de llamada Argumentos Resultado
print-int 1 $a0=entero
print-float 2 $f12=valor en FP32
print-double 3 $f12=valor en FP64
print-string 4 $a0=buffer
read-int 5 Entero leído en $v0
read-float 6 FP32 leído en $f0
read-double 7 FP64 leído en $f0
read-string 8 $a0=buffer, Se almacena la cadena leída partir de la
$a1=longitud dirección contenida en $a0
exit 10
print-char 11 $a0=carácter
read-char 12 Carácter leído en $v0

También podría gustarte