Necesito documentación de MIPS

Moderadores: Kravenbcn, largeroliker, fidelcastro, cerealkiller, pspCaracas, m0skit0, LnD, ka69, zacky06

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

Re: Necesito documentación de MIPS

Mensaje por m0skit0 »

dRoLl3R escribió:Lo que necesitaba era la codificación de las instrucciones de x86 para compararlas con las de MIPS y eso no me no lo he conseguido encontrar.
dRoLl3R escribió:Lo que necesitaba era la codificación de las instrucciones de x86 para compararlas con las de MIPS y eso no me no lo he conseguido encontrar.

Gracias, mis poderes de adivinación no llegaban para tanto.

Como siempre, Google es tu colega. La codificación de instrucciones MIPS ya te la pasé en la documentación antes referida. Las de x86 pues simple y llanamente en la página de Intel. Esto no es la PSP, el PC es un formato abierto ;)

Igualmente, a todo esto, te siguen valiendo nuestras respuestas de antes junto con estos manuales, ya que puedes directamente comparar operaciones que se encuentren en ambas arquitecturas como ADD.

Ah, y si quieres comparte con nosotros las conclusiones que saques de la comparación y a ver tu opinión sobre ambos ;)
Imagen

Avatar de Usuario
dRoLl3R
Habitual
Habitual
Mensajes: 315
Registrado: 29 Sep 2009, 21:30
Ubicación: [ † ] Asturias

Re: Necesito documentación de MIPS

Mensaje por dRoLl3R »

Gracias m0skito, de todas formas el trabajo lo hemos tenido que subir al campus virtual hoy y no he incluido la codificación de cada instrucción sino que he explicado como se codifican ;)

En cuanto lo que es comparación, no sabia como comparar la codificación ya que al fin y al cabo son ceros y unos, así que simplemente plasme las codificaciones de MIPS y la forma de codificar de x86.

De los apartados que hay en el primer post yo me encargaba de la longitud de palabra y de los procedimientos.

Os dejo aquí en un spoiler el trabajo ;)
Spoiler:
Comparación entre las arquitecturas x86-32 y MIPS

1. COMPARACIÓN DE LOS TAMAÑOS DE PALABRA.

Para comparar los tamaños de palabra de cada arquitectura es necesario saber qué es lo que se va a almacenar en esas palabras. Los procesadores usan en su lenguaje unos operandos, ya sean datos almacenados en registros, en memoria o inmediatos, que varían dependiendo de la arquitectura.

x86-32:

En la arquitectura x86-32 existen datos de distintos tamaños: el byte (8 bits), la palabra o word (16 bits) y la doble palabra o double word (32 bits). Dentro de estos datos podemos acceder a otros. En la palabra podemos acceder a su byte más y menos significativo y en la doble palabra podemos acceder a la palabra más y menos significativa.

En esta arquitectura una posición de memoria puede almacenar 8 bits. Esto provoca que en una posición solo entre un byte y no una palabra o doble palabra. Para almacenar estos datos se sigue el criterio little-endian de manera que se almacenan los bytes de la palabra en posiciones de memoria contiguas situándose el byte menos significativo en la posición de memoria más baja y el más significativo en la más alta. El ancho de direcciones de memoria es de 32 bits por lo que se dispone de un espacio de direcciones de 4 Gigapalabras.

MIPS:

En la arquitectura MIPS existen datos de distintos tamaños: el bit (1 bit), el nibble (4bits), el byte (8 bits), la media palabra o half word (16 bits), la palabra o word (32bits) y la doble palabra o double word (64bits). En esta arquitectura se pueden mover bytes, medias palabras y palabras desde registro a memoria y viceversa pero no se pueden mover dobles palabras.

En esta arquitectura una posición de memoria puede almacenar 8 bits. Esto provoca que en una posición solo entre un byte y no media palabra o palabra. Para almacenar estos datos se colocan en varias direcciones de memoria contiguas siguiendo un criterio. En esta arquitectura podemos usar el criterio little-endian que usa x86-32 o el big-endian en el que el byte menos significativo se almacena en la posición más alta y el más significativo en la más baja. El ancho de direcciones de memoria es de 32 bits por lo que se dispone de un espacio de direcciones de 4 Gigapalabras.

Los datos que ocupan 64 bits se almacenan en parejas de registros par-impar de la unidad de coma flotante (FPU).



x86-32 MIPS
Ancho de la arquitectura 32 32
Ancho de las posiciones de memoria 8 8
Ancho de las direcciones de memoria 32 32
Tamaño del espacio de direcciones 4 Gigapalabras 4 Gigapalabras


2. COMPARACIÓN DE LOS JUEGOS DE REGISTROS.


En arquitectura de ordenadores, los registros son elementos fundamentales. S tratan de memorias de alta velocidad y poca capacidad, integradas en el microprocesador, que permiten guardar transitoriamente y acceder a valores muy usados, generalmente en operaciones matemáticas. Gracias a estas características y otras más complejas en las que no entraremos, los registros son la manera más rápida que tiene el sistema de almacenar datos, existen registros de muchos tipos y tamaños dependiendo de la arquitectura, nosotros compararemos los registros de la arquitectura x86-32 con los de MIPS:

x86-32:


En esta arquitectura existen 8 registros de propósito general de 32 bits, su nombre se indica con 3 letras mayúsculas siendo la primera la E (por ejemplo EAX ). Pero luego a la hora de programar en lenguaje ensamblador se puede eliminar la E, y escribirlos con sus otras dos letras, con el objeto de acceder a su palabra menos significativa. Estos registros, salvo el registro ESP que siempre se usa para lo mismo, teóricamente son libres, es decir, se puede almacenar cualquier valor binario en ellos, independientemente del valor que represente en nuestro programa, pero a niveles de programación en ensamblador de alto nivel, a cada uno se le da un uso concreto , son los siguientes:

EAX Acumulador, de uso general.
EBX Registro base, de uso general.
ECX Registro contador, de uso general.
EDX Registro de datos, de uso general.
En estos primeros 4 registros a su vez también podemos acceder a su byte más significativo, suprimiendo la E y sustituyendo la X por H (High) en el caso de que queramos acceder a la parte alta, o sustituyendo la X por L (Low) en el caso de que queramos acceder a la parte baja.
EBP Registro de apuntadores base. Se utiliza para copiar la dirección de los parámetros almacenados en la pila.
ESI Registro índice fuente.
EDI Registro índice destino.
ESP Registro del apuntador de la pila. Este registro nos indica dónde está la pila en la que se guardan los datos que introducimos en ella.
En esta arquitectura existen también otros tipos de registros, como los registros de segmento como CS,DS,ES,FS,GS y SS que nos indican donde se encuentra un segmento determinado, en qué segmento se encuentra la pila, o el código que estamos ejecutando.

El registro IP apunta a la siguiente instrucción que se tiene que ejecutar y el registro F se corresponde con el registro de FLAGS.


Además en los últimos años (1997-99) esta arquitectura ha añadido una serie de registros extra pero en los que ya no entraremos a analizar, son los registros del tipo MMX, 3DNow, SSE, por citar algunos de los más importantes en la actualidad.

MIPS:

A diferencia de la anterior arquitectura, MIPS dispone de hasta 32 registros de propósito general de 32 bits. Su nombre es siempre del tipo rX, donde X es un número entre 0 y 31 ambos inclusive, tal y como pasaba en x86-32 estos registros pueden almacenar cualquier valor, salvo el primero ,r0, que almacena la constante 0 y recibe el nombre de zero, pero a la hora de programar a un nivel considerable se les llama por otros nombres distintos de los que se citaron ( suele ser con una letra minúscula y un número o dos letras minúsculas ) con objeto de diferenciarlos según los valores que cada uno está destinado a almacenar, a continuación veremos la lista con los dos nombres y el uso que se les da.

r0, zero : Almacena la constante 0.
r1, at : Se usa para almacenar cualquier valor que sea necesario en programación ensamblador.
r2-r3, vo-v1: Almacenan los resultados de las funciones.
r4-r7, a0-a3: Almacenan los parámetros que se pasan a las funciones.
r8-r15, r24-r25, t0-t9 : Son los registros temporales, es decir, en ellos no se guarda ningún valor entre llamadas.
r16-r23, s0-s7 : Son los registros salvados, es decir, en ellos se guarda el valor entre llamadas.
r26-r27, k0-k1 : Son los registros reservados para el núcleo ( kernel) del sistema operativo.
r28, gp : Es el puntero de área global.
r29, sp : Es el puntero de pila.
r30, fp : Es el puntero de marco de pila.
r31, ra : ( return adress ) Almacena la dirección de retorno, cuando es llamado algún procedimiento.
Además de estos registros, en MIPS también existen algunos registros de propósito específico, en los cuales siempre se almacena el mismo valor directamente, son los siguientes:

HI: En él se almacenan los 32 bits más significativos del resultado de un producto, o del resto de una división.
LO: En el se almacenan los 32 bits menos significativos del resultado de un producto, o del cociente en una división.
PC: Contador de programa. Como ya sabemos, al inicio de cada ciclo, almacena la dirección de memoria que contiene la instrucción que se va a ejecutar.
Por último MIPS también posee 32 registros de 32 bits f0-f31, para almacenar las unidades en coma flotante, suelen estar en IEEE754.

3. COMPARACIÓN DE LOS JUEGOS DE INSTRUCCIONES Y SU CODIFICACIÓN.

Un juego de instrucciones es el conjunto de todos los comandos que, usados en programación en ensamblador, la CPU diseñada por una determinada arquitectura puede entender y ejecutar. El término describe los aspectos del procesador generalmente visibles a un programador, incluyendo las instrucciones, los registros, la arquitectura de memoria y las interrupciones, entre otros aspectos. Luego para que estas instrucciones sean procesadas correctamente por el computador tienen que ser traducidas a binario, para ello poseen una determinada codificación binaria. A continuación compararemos los juegos de instrucciones de las dos arquitecturas, junto con su correspondiente codificación.

MIPS:

ADD $d, $s, $t: Suma con signo dos registros $s y $t y guarda el resultado en otro registro $d.
0000 00ss ssst tttt dddd d000 0010 0000

ADDI $t, $s, imm: Suma a un registro $s un valor inmediato con signo y guarda el resultado en otro registro $t.
0010 00ss ssst tttt iiii iiii iiii iiii
ADDIU $t, $s, imm: Suma a un registro $s un valor inmediato sin signo y guarda el resultado en otro regsitro $t.
0010 01ss ssst tttt iiii iiii iiii iiii
ADDU $d, $s, $t: Suma sin signo dos registros $s y $t y guarda el resultado en otro registro $d.
0000 00ss ssst tttt dddd d000 0010 0001
AND $d, $s, $t: Realiza la operación AND entre dos registros $s y $t y guarda el resultado en otro registro $d.
0000 00ss ssst tttt dddd d000 0010 0100
ANDI $t, $s, imm: Realiza la operación AND entre un registro $s y un valor inmediato y guarda el resultado en otro registro $t.
0011 00ss ssst tttt iiii iiii iiii iiii
BEQ $s, $t, offset: Salta offset posiciones si los registros $s y $t son iguales.
0001 00ss ssst tttt iiii iiii iiii iiii
BGEZ $s, offset: Salta offset posiciones si el registro $s es igual o mayor que cero.
0000 01ss sss0 0001 iiii iiii iiii iiii
BGEZAL $s, offset: Salta offset posiciones si el registro $s es igual o mayor que cero y guarda el resultado en $31.
0000 01ss sss1 0001 iiii iiii iiii iiii
BGTZ $s, offset: Salta offset posiciones si el registro $s es mayor que cero.
0001 11ss sss0 0000 iiii iiii iiii iiii
BLEZ $s, offset: Salta offset posiciones si el registro $s es igual o menor que cero.
0001 10ss sss0 0000 iiii iiii iiii iiii
BLTZ $s, offset: Salta offset posiciones si el registro $s es menor que cero.
0000 01ss sss0 0000 iiii iiii iiii iiii
BLTZAL $s, offset: Salta offset posiciones si el registro $s es menor que cero y guarda el resultado en $31.
0000 01ss sss1 0000 iiii iiii iiii iiii
BNE $s, $t, offset: Salta offset posiciones si los registros $s y $t no son iguales.
0001 01ss ssst tttt iiii iiii iiii iiii
DIV $s, $t: Divide con signo $s por $t y almacena el cociente en $LO y el resto en $HI.
0000 00ss ssst tttt 0000 0000 0001 1010
DIVU $s, $t: Divide sin signo $s por $t y almacena el cociente en $LO y el resto en $HI.
0000 00ss ssst tttt 0000 0000 0001 1011
J target: Salta a la dirección indicada.
0000 10ii iiii iiii iiii iiii iiii iiii
JAL target: Salta a la dirección indicada y guarda la dirección de retorno en $31.
0000 11ii iiii iiii iiii iiii iiii iiii
JR $s: Salta a la dirección contenida en el registro $s.
0000 00ss sss0 0000 0000 0000 0000 1000
LB $t, offset($s): Se carga un byte de la dirección especificada ($s + offset) en el registro $t.
1000 00ss ssst tttt iiii iiii iiii iiii
LUI $t, imm: El valor inmediato desplaza a la izquierda 16 bits y se almacenan en el registro $t. Los últimos 16 bits se convierten en 0.
0011 11-- ---t tttt iiii iiii iiii iiii
LW $t, offset($s): Una palabra es guardada en un registro $t desde la dirección dada ($s + offset).
1000 11ss ssst tttt iiii iiii iiii iiii
MFHI $d: El contenido del registro $HI se mueve al registro $d.
0000 0000 0000 0000 dddd d000 0001 0000
MFLO $d: El contenido del registro $LO se mueve al registro $d.
0000 0000 0000 0000 dddd d000 0001 0010
MULT $s, $t: Multiplica con signo los registros $s y $t y almacena el resultado en el registro $LO.
0000 00ss ssst tttt 0000 0000 0001 1000
MULTU $s, $t: Multiplica sin signo los registros $s y $t y almacena el resultado en el registro $LO.
0000 00ss ssst tttt 0000 0000 0001 1001
NOOP: no realiza ninguna operación.
0000 0000 0000 0000 0000 0000 0000 0000
OR $d, $s, $t: Realiza la operación OR entro dos registros $s y $t y guarda el resultado en otro registro $d.
0000 00ss ssst tttt dddd d000 0010 0101
ORI $t, $s, imm: Realiza la operación OR entre un registro $s y un valor inmediato y guarda el resultado en otro registro $t.
0011 01ss ssst tttt iiii iiii iiii iiii
SB $t, offset($s): El byte menos significativo de $t se guarda en la dirección indicada ($s + offset).
1010 00ss ssst tttt iiii iiii iiii iiii
SLL $d, $t, h: Desplaza el registro $t h bits a la izquierda rellenado con ceros y lo guarda en $d.
0000 00ss ssst tttt dddd dhhh hh00 0000
SLLV $d, $t, $s: Desplaza el registro $t el valor de $s bits a la izquierda rellenado con ceros y lo guarda en $d.
0000 00ss ssst tttt dddd d--- --00 0100
SLT $d, $s, $t: Si $s es menor que $t se guarda un 1 en $d. y si no se guarda un 0. Se tiene en cuenta el signo.
0000 00ss ssst tttt dddd d000 0010 1010
SLTI $t, $s, imm: Si $s es menor que el valor inmediato se guarda un 1 en $t. y si no se guarda un 0. Se tiene en cuenta el signo.
0010 10ss ssst tttt iiii iiii iiii iiii
SLTIU $t, $s, imm: Si $s es menor que el valor inmediato se guarda un 1 en $t. y si no se guarda un 0. No se tiene en cuenta el signo.
0010 11ss ssst tttt iiii iiii iiii iiii
SLTU $d, $s, $t: Si $s es menor que $t se guarda un 1 en $d. y si no se guarda un 0. No se tiene en cuenta el signo.
0000 00ss ssst tttt dddd d000 0010 1011
SRA $d, $t, h: Desplaza el registro $t h bits rellenando con el bit de signo correspondiente y guardando el resultado en $d.
0000 00-- ---t tttt dddd dhhh hh00 0011
SRL $d, $t, h: Desplaza el registro $t h bits a la derecha rellenado con ceros y guardando el resultado en $d.
0000 00-- ---t tttt dddd dhhh hh00 0010
SRLV $d, $t, $s: Desplaza el registro $t el valor de $s bits a la derecha rellenado con ceros y guardando el resultado en $d.
0000 00ss ssst tttt dddd d000 0000 0110
SUB $d, $s, $t: Resta los registros $s y $t y guarda el resultado en $d. Se tiene en cuenta el signo.
0000 00ss ssst tttt dddd d000 0010 0010
SUBU $d, $s, $t: Resta los registros $s y $t y guarda el resultado en $d. No se tiene en cuenta el signo.
0000 00ss ssst tttt dddd d000 0010 0011
SW $t, offset($s): El contenido de $t se guarda en la dirección indicada ($s + offset).
1010 11ss ssst tttt iiii iiii iiii iiii
SYSCALL: Genera una interrupción.
0000 00-- ---- ---- ---- ---- --00 1100
XOR $d, $s, $t: Realiza la operación XOR entro dos registros $s y $t y guarda el resultado en otro registro $d.
0000 00ss ssst tttt dddd d--- --10 0110
XORI $t, $s, imm: Realiza la operación OR entre un registro $s y un valor inmediato y guarda el resultado en otro registro $t.
0011 10ss ssst tttt iiii iiii iiii iiii

x86-32:

MOV eax, ebx : Copia el contenido del registro ebx (origen) en el registro ebx (destino). Pueden ser operando origen y operando destino cualquier registro o posición de memoria direccionados de las formas ya vistas, mientras que los registros tengan la misma dimensión.

XCHG eax, ebx : Intercambia el contenido de los registros eax y ebx mientras no sean registros de segmentos.

IN al o ax, dx : Transfiere datos desde el puerto indicado hasta el registro AL o AX. El puerto puede especificarse mediante una constante (0 a 255) o a través del valor contenido en dx (0 a 65535).

OUT dx, al o ax : Transfiere un byte o palabra del registro AL o AX a un puerto de salida. El puerto puede especificarse con un valor fijo entre 0 y 255 ó a través del valor contenido en el registro DX (de 0 a 65535).

ADD eax, ebx : Suma los valores de los registros eax y ebx copiando el resultado en eax. Esta operación conlleva la activación del acarreo si se desborda el registro eax durante la suma.

ADC eax, ebx : Suma los valores de los registros eax ,ebx y el bit del indicador de acarreo copiando el resultado en eax. Esta instrucción es muy útil a la hora de llevar a cabo sumas de números muy grandes ( que exceden los 16 bits ) que se deben de realizar en varios pasos.

SUB eax, ebx : Resta el contenido del registro eax al contenido del registro ebx, copiando el resultado en el registro eax. Los operandos pueden tener o no signo, pero la condición necesaria es que sean del mismo tipo, byte o palabra.

SBB eax, ebx : Resta el contenido del registro eax al contenido del registro ebx, copiando el resultado en el registro eaxSi el bit de acarreo vale 1 además resta una unidad más. Al igual que ADC resulta útil para números grandes.

DEC eax : Resta una unidad del registro eax. Hay que tener en cuenta que llevar a cabo esta operación no se modifica el bit de acarreo (CF) y no es posible detectar un desbordamiento.

INC eax : Incrementa en una unidad el registro eax. Al igual que al usar la instrucción DEC no se altera el bit de acarreo.

NEG eax : Calcula y guarda en eax el valor negativo del dato almacenado en el mismo en complemento a dos.

AND eax, ebx : Realiza una operación de AND lógico entre el registro eax y ebx, copiando el resultado en eax. Son valores tipo byte o palabra, pero ambos del mismo tipo.

OR eax, ebx : Operación análoga a la anterior, sólo que la operación lógica a efectuar es la OR.

XOR eax, ebx : Operación análoga a la anterior, sólo que la operación lógica a efectuar es la XOR.

NOT eax : Realiza la operación NOT lógico con el registro eax, invirtiendo cada uno de sus bits y sin alterar los bits de estado.

CMP eax, ebx : Resta el valor en eax de el valor de ebx sin copiar el resultado de la operación en ningún registro, pero alterando los bits de estado. Al igual que en las operaciones de suma y resta vistas antes los registros deben de tener la misma dimensión.

LOOP Inm_8 : Decrementa el registro contador CX; si CX es cero, ejecuta la siguiente instrucción, en caso contrario transfiere el control a la dirección resultante de sumar al IP el valor de 8 bits determinado que oscila entre -128 y 127.

JMP eax : Transfiere el control a la dirección almacenada en eax, es decir, copia el valor de eax a IP.

CALL destino : Transfiere el control del programa a un procedimiento, salvando previamente en la pila la dirección de la instrucción siguiente, para poder volver a ella una vez ejecutado el procedimiento. El procedimiento puede estar en el mismo segmento (tipo NEAR) o en otro segmento (tipo FAR). A su vez la llamada puede ser directa a una etiqueta (especificando el tipo de llamada NEAR -por defecto- o FAR) o indirecta, indicando la dirección donde se encuentra el puntero.

INT x : Da paso a un procedimiento de interruption del tipo x, indicado en la instrucción ( entre 0 y 255 ). En la pila se introduce al llamar a una interrupción la dirección de retorno formada por los registros CS e IP y los bits de estado.

RET : Instrucción que se incluye al final de los procedimientos y que retorna extrayendo de la pila la dirección de la siguiente dirección.

IRET : Devuelve el control a la dirección de retorno salvada en la pila por una interrupción previa y restaura los indicadores que también se introdujeron en la pila. Esta operación extrae de la pila las 3 palabras que vimos que se añadían con las instrucción INT.

PUSH ax : Decrementa el puntero de pila (SP) en 2 y luego transfiere la palabra del registro ea a la cima de la pila.

POP ax : Transfiere el elemento palabra que se encuentra en lo alto de la pila (apuntado por SP) al registro ax, de tipo palabra e incrementa en dos el registro SP.

PUSHA : Equivale a realizar PUSH con los siguientes registros, en este orden: AX, CX, DX, BX, SP, BP, SI y DI.

POPA : Equivale a realizar POP con los siguientes registros, en este orden: DI, SI, BP, SP, BX, DX, CX, AX.

Además la arquitectura Intel posee algunas instrucciones más complejas en las que no entraremos algunas de ellas referidas a la manipulación de cadenas y caracteres ACII como por ejemplo:
MOVS, LODS, STOS, CMPS, SCAS, INS, OUTS, REP, AAA, AAD, AAM, AAS, DAA, DAS
Con la arquitectura x86-32, en vez de poner todas las instrucciones codificadas, vamos a explicar cómo se codifican las instrucciones.

En esta arquitectura, cada instrucción tiene una longitud de 16 bits, es decir, una palabra.

Las instrucciones están formadas por:

Prefijo (Opcional) – Opcode (primer byte) – D – W – Opcode 2 (ocasionalmente segundo byte) – MOD – Reg – R/M – Desplazamiento o datos (ocasionalmente 1, 2 o 4 bytes)

Prefijo: Es opcional, cambia la operación de la instrucción.
Opcode: 6 bits que indican de que familia es la instrucción.
D: 1 bit que indica el la dirección de la operación. Si es un 1 el registro es el destino, si es un 0 es el origen.
W: 1 bit que indica el tamaño de la operación. Un 1 indica que es una palabra y un 0 un byte.
MOD: 2 bits que indican el modo del registro.
Reg: 3 bits que indican que registro se utiliza.
R/M: 3 bits que indican el registro o memoria que se usan como operando.
No todas las instrucciones tiene W o D, en algunos casos el tamaño de la operación es irrelevante o está implícito, y para otras operaciones la dirección es irrelevante.

MOD:

00: Si R/M es 110, la dirección del registro es un desplazamiento, si no, no hay desplazamiento.
01: Se desplazan 8 bits y se extiende el signo a los 16 bits.
10: Se desplazan 16 bits.
11: R/M se trata como un segundo registro.
Reg:

000: Si w=0, AL; Si w=1, AX; SI es doble palabra EAX.
001: Si w=0, CL; Si w=1, CX; SI es doble palabra ECX.
010: Si w=0, DL; Si w=1, DX; SI es doble palabra EDX.
011: Si w=0, BL; Si w=1, BX; SI es doble palabra EBX.
100: Si w=0, AH; Si w=1, SP; SI es doble palabra ESP.
101: Si w=0, CH; Si w=1, BP; SI es doble palabra EBP.
110: Si w=0, DH; Si w=1, SI; SI es doble palabra ESI.
111: Si w=0, BH; Si w=1, DI; SI es doble palabra EDI.
R/M:

000: BX + SI + desplazamiento (0, 1 o 2 bytes).
001: BX + DI + desplazamiento (0, 1 o 2 bytes).
010: BP + SI + desplazamiento (0, 1 o 2 bytes).
011: BP + DI + desplazamiento (0, 1 o 2 bytes).
100: SI + desplazamiento (0, 1 o 2 bytes).
101: DI + desplazamiento (0, 1 o 2 bytes).
110: BP + desplazamiento a menos que MOD = 00.
111: BX + desplazamiento (0, 1 o 2 bytes).


4. COMPARACIÓN DE LOS MODOS DE DIRECCIONAMIENTO.

Las operaciones llevadas a cabo por el ordenador requieren de operandos o datos a procesar, estos datos pueden ser obtenidos a través de varios métodos de acceso que dan lugar a diferentes modos de direccionamiento.

Debido a esto podemos definir los siguientes modos.

X86-32

INMEDIATO: el operando fuente es una constante codificada en la instrucción o definida anteriormente. El destino puede ser un registro o bien una dirección de memoria.
MOV EAX, 00FFh ; MOV [10203040h], dato

ENTRE REGISTROS: ambos operandos fuente y destino son registros.
ADD EAX, EBX
ABSOLUTO O DIRECTO: uno de los dos operandos apunta directamente a una posición de memoria. Se puede hacer referencia a una posición de memoria con la directiva OFFSET y a continuación la etiqueta asignada a ese dato.
MOV EAX, [10203040h] -.- MOV EAX, OFFSET dato

REGISTRO INDIRECTO: el operando se encuentra en una dirección señalada por un registro. Similar al anterior, pero la dirección se encuentra en un registro.
MOV EAX, [EDI]; donde edi contiene una dirección de memoria.

BASE + DESPLAZAMIENTO: en este modo la dirección efectiva se obtiene sumando un registro mas un valor almacenado como parte de la instrucción. Es equivalente al modo indirecto cuando el desplazamiento = 0.
MOV EAX,[EBX+12]

BASE + INDICE: similar al anterior pero en este caso la dirección se obtiene de la suma de dos registros de propósito general.
MOV EAX, [EBX+ESI]

INDICE ESCALADO + DESPLAZAMIENTO: está formado por un registro multiplicado por un factor constante (potencia de 2) que es el desplazamiento y a este se le suma un desplazamiento.
MOV EAX, [ESI*4 + 8]

BASE + INDICE ESCALADO + DESPLAZAMIENTO: Combinación de los modos base+índice e índice escalado + desplazamiento.
MOV EAX, [EBP+ESI*4+8]

Pueden considerarse también los modos AUTO-INCREMENTADO y AUTO-DECREMENTADO para las instrucciones PUSH y POP respectivamente que hacen uso de la pila y por tanto deben cambiar la posición de memoria sobre la que trabajan.

MIPS

Al igual que en Intel un operando puede estar en memoria, en un registro o en la propia instrucción.

Al ser MIPS una arquitectura de carga/almacenamiento sólo las instrucciones load y store tienen acceso a la memoria. Las instrucciones que realizan cálculos operan solamente sobre valores en registros.

MIPS consta de los modos de direccionamiento

INMEDIATO: se codifica en la propia instrucción un valor constante al igual que Intel.
lw $t0, 0x12345678

DIRECTO A REGISTRO: tanto operando fuente como destino pueden ser registros.
lw $t0, ($t3) ; add $t1, $t2, $t3

BASE + DESPLAZAMIENTO: el operando se encuentra en una posición de memoria cuya dirección es la suma de un registro más una constante.
lw $t0, 0x12345678($t1)

Las direcciones de memoria pueden ser sustituidas por identificadores también añadiendo instrucciones de la forma.

lw $registro, identificador+Inmediato($registro)

RELATIVO AL PC: la dirección es la suma del PC y la constante codificada en la instrucción.
bgez $t1, instr1; instrucción de salto relativa al PC
PSEUDODIRECTO: donde la dirección de salto son los 26 bits de la instrucción concatenados con los bits de mayor peso del PC.
j instr2 ; Salta a la dirección indicada


5. COMPARACIÓN DE LAS INSTRUCCIONES DE SALTO CONDICIONAL.

Las instrucciones de salto condicional son una parte fundamental de la programación. Se trata de la posibilidad de ejecutar un determinado fragmento de código u otro dependiendo de la situación. Esto a nivel de ensamblador se consigue con instrucciones similares a los JMP que ya hemos visto, pero que se ejecutan o no dependiendo de la situación. Esto es lo que ocurre en general, pero ahora vamos a ver con más detalle como se llevan a cabo los saltos condicionales en estas dos arquitecturas:


X86-32:


La forma de implementar una sentencia condicional en esta arquitectura, coincidiendo con el método general, es realizar una comparación, cuyo resultado variará dependiendo de la situación, y posteriormente un salto. En esta arquitectura no es necesario fijarse en los bits de estado ya que, además de las instrucciones que ya conocemos del computador teórico que realizan saltos en función del valor de un determinado bit de estado, existen una serie de instrucciones que realizan saltos cuando se den determinadas condiciones, lo que a la hora de programar es mucho más práctico.


Un salto siempre tiene que estar precedido de la instrucción CMP, que como ya vimos, restaba dos valores de dos registros, pero no almacenaba la solución, después de esta comparación es donde se incluye una de las instrucciones siguientes, que hace referencia a una condición que se tuvo que cumplir en esa comparación, y a una etiqueta, a la que saltará, alterando el valor del registro IP, al que se le sumará un número dependiendo de la situación de esa etiqueta en memoria.


Las instrucciones de salto condicional se usan combinando letras que tienen distintos significados que veremos ahora, todas comienzan con la J de salto ( jump ):


J Jump (saltar)
E Equal (igual)
N Not (no)
G Greater than (Mayor que) Magnitudes con signo
L Less than (Menor que) Magnitudes con signo
A Above (Mayor que) Magnitudes sin signo
B Below (Menor que) Magnitudes sin signo


Con estas letras se pueden construir todas las instrucciones condicionales que implican comparación de valores numéricos, son estas:


JE eax, ebx Salta si los dos valores comparados son iguales
JNE eax, ebx Salta si los dos valores comparados son distintos
JA o JNBE (sin signo) y JG o JNLE (sin signo) eax, ebx Salta si el valor de eax es mayor que el de ebx.
JAE o JNB (sin signo) y JGE o JNL (sin signo) eax, ebx Salta si el valor de eax es mayor o igual que el de ebx.
JB o JNAE (sin signo) y JL o JNGE (sin signo) eax, ebx Salta si el valor de eax es menor que el de ebx.
JBE o JNA (sin signo) y JLE o JNG (sin signo) eax, ebx Salta si el valor de eax es menor o igual que el de ebx.


Así un ejemplo de salto sería:


cmp eax, ebx // se realiza la comparación


jg etiqueta // si eax es mayor que ebx salta a la etiqueta, sino continúa el transcurso del programa


código1…


etiqueta: //señalización de la etiqueta a donde saltará y desde donde se seguirá ejecutando el código


código2…


Ahora acabamos de ver como tenemos la posibilidad de ejecutar una porción de código ( código 1) o no, pero para solventar el problema de tener que ejecutar una porción de código u otra se usa la instrucción JMP etiqueta:, como demostraremos a continuación.


cmp eax, ebx // se realiza la comparación


jg etiqueta // si eax es mayor que ebx salta a la etiqueta, sino continúa el transcurso del programa


código1…


jmp salto // si se ha ejecuta esta parte de código se saltará a la etiqueta, evitando ejecutar la otra porción


etiqueta: //señalización de la etiqueta a donde saltará y desde donde se seguirá ejecutando el código


código2…


salto: // señalización de la etiqueta a donde se saltará siempre que se ejecute el codigo1.


MIPS:


En MIPS la principal diferencia con x86-32 es que no necesitamos una sentencia de comparación previa para realizar los saltos condicionales, sino que la instrucción ya implica comparación, condición, no basada en los bits de estado, y salto a una etiqueta. También MIPS nos ofrece la opción de guardar la dirección actual en el registro de retorno ra, que ya hemos visto. Pero, al igual que en x86-32, estas instrucciones también se componen de letras, cuyos significados son los siguientes:

b salto condicional con comparación
eq igual ( para indicar igual pero en los casos de mayor o menor igual se utiliza solo la “e”)
z cero
u comparación de magnitudes sin signo
g mayor
al indica que se guarda la dirección actual en el registro ra
t indica que no es mayor o menor igual, sino que estricto
n indica negación
j salto incondicional
r indica salto a una dirección almacenada en un registro


Así tenemos las siguientes instrucciones:


beq Rsrc1, Src2, etiqueta : Salto condicional si Rsrc1 es igual a Src2.
beqz Rsrc, etiqueta : Salto condicional si el registro Rsrc es igual a 0.
bge Rsrc1, Src2, etiqueta : Salto condicional si el registro Rsrc1 es mayor o igual a Src2 (con signo).
bgeu Rsrc1, Src2, etiqueta : Salto condicional si el registro Rsrc1 es mayor o igual a Src2 (sin signo).
bgez Rsrc, etiqueta : Salto condicional si el registro Rsrc es mayor o igual a 0.
bgezal Rsrc, etiqueta : Salto condicional si el registro Rsrc es mayor o igual a 0. Guarda la dirección actual en el registro ra.
bgt Rsrc1, Src2, etiqueta : Salto condicional si el registro Rsrc1 es mayor que Src2 (con signo).
bgtu Rsrc1, Src2, etiqueta : Salto condicional si el registro Rsrc1 es mayor que Src2 (sin signo).
bgtz Rsrc, etiqueta : Salto condicional si Rsrc es mayor que 0.
ble Rsrc1, Src2, etiqueta : Salto condicional si Rsrc1 es menor o igual a Src2 (con signo).
bleu Rsrc1, Src2, etiqueta : Salto condicional si Rsrc1 es menor o igual a Src2 (sin signo).
blez Rsrc, etiqueta : Salto condicional si Rsrc es menor o igual a 0.
bltzal Rsrc, etiqueta : Salto condicional si Rsrc es menor que 0. Guarda la dirección actual en el registro ra.
blt Rsrc1, Src2, etiqueta : Salto condicional si Rsrc1 es menor que Src2 (con signo).
bltu Rsrc1, Src2, etiqueta : Salto condicional si Rsrc1 es menor que Src2 (sin signo).
bltz Rsrc, etiqueta : Salto condicional si Rsrc es menor que 0.
bne Rsrc1, Src2, etiqueta : Salto condicional si Rsrc1 no es igual a Src2.
bnez Rsrc, etiqueta : Salto condicional si Rsrc no es igual a 0.
j etiqueta : Salto incondicional.
jal etiqueta : Salto incondicional, almacena la dirección actual en ra.
jalr Rsrc : Salto incondicional a la dirección almacenada en Rsrc, almacenando la dirección actual en ra.
jr Rsrc : Salto incondicional a la dirección almacenada en Rsrc.


Por lo demás a la hora de las formas que tiene para ejecutar una porción de código o no, o ejecutar una de entre dos o más es análogo a la arquitectura anterior, sustituyendo la comparación y la instrucción condicional de x86-32, por una única instrucción de las que acabamos de mostrar en MIPS.


6. COMPARACIÓN DE LAS INSTRUCCIONES PARA EL DESARROLLO DE PROCEDIMIENTOS.

Los procedimientos o subrutinas son el elemento fundamental de la programación estructurada. El uso de estos ayuda a la comprensión del código y posibilita su reutilización.

Los procedimientos son fragmentos de códigos que pueden ser llamados y ejecutados desde cualquier punto del programa. Estos procedimientos pueden o no efectuar acciones con información que recibe por parámetros (se dice que están parametrizados).

Cuando se llama a un procedimiento se sigue un orden en las acciones que se van a realizar.

Se envían parámetros al procedimiento de alguna manera, ya sea la memoria o los registros.
Se transfiere el hilo de ejecución al código del procedimiento.
Se reserva espacio de almacenamiento para realizar la ejecución dentro del procedimiento ya sea mediante registros o memoria. Normalmente se utiliza la memoria ya que los registros son muy limitados.
Se ejecuta el código del procedimiento.
Se almacena el resultado en donde el código que llamo al procedimiento pueda acceder.
Se retorna al lugar desde donde se ha llamado al procedimiento.
Para poder utilizar la memoria como almacén de datos temporales de una forma sencilla se recurre al concepto de pila. La pila es una estructura de datos formada por un conjunto deposiciones de memoria contiguas. La pila es una estructura LIFO (Last In First Out), el último dato que entra en la pila es el primero en salir de ella. Para ello se ha de disponer dueña referencia a la posición de memoria donde está el último dato introducido(cima). La cima suele estar almacenada en un registro llamado puntero de pila.

Los procedimientos que requieran la pila necesitan un puntero auxiliar para recorrerla. Este puntero se almacena en un registro y se decrementa o incrementa para acceder a una posición concreta sin modificar el puntero de la pila.

La operación mediante la que se introducen datos en la pila se denomina PUSH(apilar) y la que los saca y los lee POP(desapilar).

x86-32:

En la arquitectura x86-32, el funcionamiento de la pila es parecido a lo explicado. Para introducir datos se utiliza la instrucción PUSH y para sacarlos y leerlos la instrucción POP.El puntero de pila, la referencia a la cima de la pila, es el registro ESP y el puntero auxiliar es el registroEBP. Como en esta estructura los datos que ocupan doble palabra no entran en una posición de memoria y se utilizan cuatro, cuando se apila un dato en la memoria el puntero se decrementa en cuatro posiciones y cuando se desapila se incrementa también cuatro posiciones.

MIPS:

En la arquitectura MIPS, el funcionamiento de la pila varía un poco a lo explicado anteriormente. A diferencia de muchas otras arquitecturas, MIPS no tiene instrucciones para apilar y desapilar datos (PUSH y POP). A pesar de ello existe una convención en la implementación de la pila. Se reserva el registro sp como puntero de la pila y el programador es el responsable de modificar el valor del registro si se almacena o se extrae un valor de la pila. Como el valor del puntero de la pila no varía, la pila puede crecer hacia posiciones altas o bajas de la memoria pero por los precedentes históricos crece hacia posiciones bajas de manera que la cima de la pila es la posición más baja de la memoria, al igual que en x86-32.


Procedimientos con pasos de parámetros a través de los registros:

Como ya hemos mencionado, el paso de parámetros en los procedimientos se puede realizar a través de los registros o de la memoria. En el caso de usar los registros se debe almacenar los parámetros en registros antes de llamar al procedimiento y el procedimiento tiene que devolver el resultado mediante otro registro.

En el caso de la arquitectura x86-32, se puede usar cualquier registro de propósito general.

En la arquitectura MIPS existen cuatro registros para pasar parámetros a los procedimientos (a0, a1, a2 y a3) y dos registros para devolver el resultado de las operaciones (v0 y v1).

Para las variables locales también se pueden usar registros.

En la arquitectura x86-32, se suele usar más la pila debido al número limitado de registros.

En MIPS existen diez registros para guardar variables locales (t0, t1, …, t9).

Procedimientos con paso de parámetros a través de la pila:

Para pasar parámetros a los procedimientos a través de la memoria se utiliza la pila. De esta manera no es necesario modificar registros para realizar operaciones dentro del procedimiento. Para ello se mete en la pila los datos necesarios antes de llamar a los procedimientos. Una vez dentro del procedimiento se salvaguardan en la pila los datos de los registros que vayamos a utilizar durante su ejecución.Antes de esto se tiene que haber hecho una copia del puntero de pila en el puntero auxiliar de manera que con él podamos acceder al parámetro sin modificar el puntero principal. Una vez finalizada la ejecución del procedimiento se desapilan los datos de los registros utilizados recuperando el estado que tenían antes de llamar al procedimiento y se eliminan las variables locales y los parámetros. El dato que se devuelve como resultado se devuelve a través de un registro.

En x86-32, el proceso es el que acabamos de explicar. En esta arquitectura tenemos que tener especial cuidado con no modificar el puntero de la pila ya que la dirección de retorno del procedimiento se guarda en la pila. Sin embargo, en MIPS, al no existir PUSH yPOP no es necesario el puntero auxiliar ya que se puede manejar el valor del registro sp (Stack Pointer) con comodidad. En MIPS, la dirección de retorno se guarda en el registro ra por lo que antes de llamar a un procedimiento hay que guardar el valor de ese registro en la pila. Los registros que se usan dentro de los procedimientos son ocho (s0-s7) y es necesario salvaguardarlos en la pila para no perder los datos que contengan. Como ocurría en el paso de parámetros a través de registros, el resultado se devuelve a través de los registros v0 y v1 .

Instrucciones de llamada y retorno de procedimientos:

Como ya hemos mencionado, los procedimientos pueden ser llamados desde cualquier parte del código del programa y cuando finaliza debe devolver el hilo de la ejecución al lugar desde donde se le llamo. Para llamarlos disponen de una etiqueta con un nombre que describa su utilidad.

x86-32:

Después de almacenar los parámetros en registros o en la pila se ha de llamar al procedimiento. Para ello se utiliza la instrucción CALL Etiqueta (donde Etiqueta es el nombre del procedimiento). La instrucción CALL almacena en la pila la dirección de retorno, es decir, la dirección a la instrucción que está después del CALL.Cuando finaliza el procedimiento se utiliza la instrucción RET para devolver el hilo de ejecución al código principal. Lo que hace el RET es coger la última dirección almacenada en la pila y continuar la ejecución desde esa dirección.Debido a esto hay que tener mucho cuidado con la utilización de la pila dentro del procedimiento. Después de volver al código principal es necesario eliminar de la pila los parámetros que hayamos utilizado. Para ello se incrementa el puntero de pila la cantidad necesaria.

MIPS:

Al igual que en x86-32 existe una instrucción para llamar al procedimiento que almacena la dirección de retorno.Esa instrucción es JAL Etiqueta (donde Etiqueta es el nombre del procedimiento). A diferencia de x86-32, la dirección de retorno no se almacena en la memoria, sino que se almacena en un registro utilizado para ese fin, el registro ra. Esto permite que la ejecución de la instrucción JAL se realice en un solo ciclo de reloj ya que si se hiciese en la memoria conlleva más ciclos debido a la escritura en memoria. Cuando finaliza el procedimiento se llama a la instrucción JR que continua con la ejecución en la dirección que contiene el registro ra.




x86-32 MIPS
Llamar al procedimiento cuyo nombre es Etiqueta. CALL Etiqueta JAL Etiqueta
Retornar el procedimiento. RET JR


7. COMPARACIÓN DE FRAGMENTOS DE CÓDIGO.

Programa HOLA MUNDO

X86
MIPS
.model small
.stack ;sería para definir la pila
.data ;declaración de datos
Cadena1 DB 'Hola Mundo.$'
.code ; comienzo del código
programa:
mov ax, @data ; mueve al registro la dirección de los datos
mov ds, ax ;almacena dirección de un segmento de datos
mov dx, offset Cadena1 ; obtiene la dirección de la cadena
mov ah, 9 ; esta es la función para visualizar cadenas
int 21h ; sirve para mostrarlo en pantalla MSDOS
end programa
.data ;Declaración de variables
cadena: .asciiz "Hola Mundo \n"
.text ; indica el comienzo del código
.globl main ;indica donde comenzará a ejecutarse
main:
la $a0 cadena ;carga en el registro la dirección de memoria donde comienza "cadena"
li $v0 4 ;este es el código para imprimir String
syscall ; imprime la cadena
li $v0 10 ; código para salir
syscall ;sale del programa

Se muestra en esta tabla el sencillo programa hola mundo en las dos arquitecturas donde se aprecia principalmente la diferencia para obtener la cadena a imprimir.



Programa que suma dos números.

X86
MIPS
.386
.model flat
.data
numero1 DW 100 ; define el primer operando
numero2 DW -10 ; se define el segundo operando
resultado DW ?; se reserva memoria para el resultado
.code
inicio:
mov ax, numero1 ; mueve el valor del primer número a ax
mov bx, numero2 ; mueve el valor del segundo número a bx
add ax,bx ; asigna la suma de los dos números al registro ax
mov resultado, ax
end inicio
.data
numero1: .word 100 #Se define el primer operando
numero2: .word -10 #Definición del segundo operando
resultado: .space 4 #Reserva 4 bytes en memoria
.text
.globl main
main:
lw $t0 numero1 #$t0=contiene el valor de la etiqueta "numero1"
lw $t1 numero2 #$t1=contiene el valor de la etiqueta "numero2"
add $t0 $t0 $t1 #$t0=contiene la suma de los dos números
la $t1 resultado #$t1=contiene la dirección de memoria para el resultado
sw $t0 ($t1) #Guarda el resultado obtenido
li $v0 10
syscall #exit


8. RESUMEN GLOBAL DE LA COMPARACIÓN.

En cuanto a la longitud de palabra podemos resumir que son similares ya que ambas tienes el mismo ancho para las posiciones de memoria, para las direcciones y de la arquitectura en general.

A nivel de registros podemos concluir que ambas arquitectura usan registros de 32 bits, siendo MIPS la que tiene un surtido más amplio y variado de registros de propósito general además de un soporte de 32 registros para almacenar las unidades en coma flotante. Por otro lado x86-32 nos aporta más versatilidad al poder acceder a distintas partes de sus registros con solo suprimir o sustituir unas letras y además tiene mayor diversidad y cantidad de registros de propósito específico, sin olvidarnos de los nuevos registros que se van añadiendo con el tiempo.

En cuanto a los procedimientos encontramos cierta similitud en las instrucciones ya que en ambas arquitecturas se llama al procedimiento y se almacena la dirección de retorno con una única instrucción. La diferencia es que en MIPS la dirección de retorno se almacena en un registro y en x86-32 en la pila. Otra diferencia es el tratamiento de la pila ya que MIPS no contempla instrucciones para apilar y desapilar como x86-32. Las instrucciones de retorno de la pila también son parecidas con la salvedad de que una mira en la pila y la otra en el registro correspondiente.

En síntesis podemos concluir que MIPS nos ofrece un abanico más amplio de posibilidades en los saltos, tanto condicionales como sino, al tener la posibilidad de implementar en una única orden la comparación, el salto a memoria y fundamentalmente el almacenamiento de la dirección en la que se encontraba el programa. Por otra parte la arquitectura x86-32 es mucho más sencilla en el aspecto sintáctico y además nos da la posibilidad de realizar saltos en base al valor de los bits de estado.

Referente a los modos de direccionamiento la arquitectura X86 es mas completa que MIPS, aunque ninguna de las dos arquitecturas permite direccionamiento de memoria a memoria MIPS solo permite acceder a memoria a las instrucciones de carga y almacenamiento, teniendo que realizar las demás operaciones a través de los registros que proporciona.

PD: siento el desastre de algunos apartados como el de comparacion de codigo y las tablas ya que al ser copy-paste se pierde el formato. ¿Es posible copiar el formato html en el foro?
PSP3ooo: 4.21 -> 5.00 -> 5.03 -> 5.03 GEN-A -> 5.03 M33 -> 5.03 MHU -> 5.03 GEN-C -> 5.03 MHU -> 6.20 PRO-B4

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

Re: Necesito documentación de MIPS

Mensaje por m0skit0 »

dRoLl3R escribió:En cuanto lo que es comparación, no sabia como comparar la codificación ya que al fin y al cabo son ceros y unos

Sí, los coches también es metal, plástico y caucho, pero no son todos iguales, ¿verdad? :lol: Compararlas significa entender cómo han sido generadas y cuál formato te parece mejor y/o peor y por qué.

dRoLl3R escribió:siento el desastre de algunos apartados como el de comparacion de codigo y las tablas ya que al ser copy-paste se pierde el formato. ¿Es posible copiar el formato html en el foro?

No, no es posible incluir HTML en el foro porque eso supondría un agujero de seguridad considerable. Sin embargo si usas las etiquetas de [code] te dejará el formato.

Saludos.
Imagen

Responder