SET 39 Call For Papers

¿Eres un hacker? Si deseas pasar a formar parte de la historia del hacking hispano, colabora con la próxima edición de SET 39 enviándonos un artículo. No esperes más, esta es tu oportunidad de demostrar lo que sabes. Ayúdanos a construir una revista de hackers para hackers. SET Staff

MIPS R2000

      4787

Autor: YbY
-[ 0x06 ]--------------------------------------------------------------------
-[ MIPS R2000 ]--------------------------------------------------------------
-[ by YbY   ]---------------------------------------------------------SET-23-



==============================================================================
                       EL MICROPROCESADOR MIPS R2000    
                                 by YbY                 
==============================================================================
        
    Bueno, en primer lugar supongo que os preguntareis que por que carajo
escribo sobre este procesador, al que no conoce ni su padre. Bueno, pues 
aunque el nombre no os suene mucho os dire que sus "hermanos mayores" 
(la gama de procesadores MIPS R3000+) son los que se utilizan en algunas 
maquinillas bastante utilizadas, como son la Playstation de Sony (R3000)
o algunas estaciones graficas Silicon Graphics. La curiosidad sobre este 
tema me vino con un articulillo que escribio el miembro de SET Green Legend
sobre hackear la Playstation. El autor adjuntaba con su articulo varias
utilidades para hacer virguerias con la consola, y un fichero llamado 
R3000.TXT, que era un texto de referencia sobre el procesador. Se decia en
el fichero que era bastante util para ver algunos volcados de codigo de la
Play, y os puedo asegurar que asi es ;)
Este articulo solo pretende ser un texto introductorio al micro. Si alguien
sabe mas y le apetece escribir que lo haga (por favor que alguien escriba
algo XDDD). Ademas: no hemos empezado el 2000 hace poco, pues que mejor 
manera de comenzar el a~o };-> ?????

$ SPIM: el simulador $
----------------------
El SPIM (MIPS al reves) es el simulador que puedes utilizar para probar lo
que diga en este articulo. Segun tengo entendido hay bastantes versiones
para plataformas PC por ahi, pero no me he detenido en buscarlos, la verdad.
Os dire una sitio FTP donde quiza haya una version vieja para sistemas
UNIX con y sin X-Window: ftp.cs.wisc.edu (directorio /pub/spim).
Si esto ya no esta disponible, pues ya sabeis: a buscar con cualquier motor
de busqueda ;)

$ Lo basico $
-------------
Bueno, vamos a empezar ya sin contemplaciones. El MIPS es un procesador
con arquitectura RISC (Reduced instruction set computer->computadoras con
un juego de instruccion reducido). Esto significa que da prioridad a las
operaciones mas utilizadas (en realidad los procesadores RISC actualmente
no tienen exactamente un "juego de instrucciones reducido"). En cambio, las
menos utilizadas se ralentizan bastante. Ademas, es bastante mas facil 
dise~ar un procesador RISC que uno CISC (los CISC son los que tienen un
juego de instrucciones mas a lo bestia). Por otro lado, la arquitectura
del micro es Harvard, es decir, que la memoria esta dividida en dos modulos:
uno para instrucciones ejecutables y otro para los datos (esto se llama
memoria segregada en la jerga tecnica).

$ Los registros $
-----------------
Como sabreis por el curso de ASM de Araghorn, en la UCP (Unidad Central de
Proceso) estan situados una serie de biestables que forman el banco de 
registros. Los registros son mas o menos como la memoria, pero a ellos se
puede acceder mas rapidamente, entre otras muchas cosas porque estan mas
cerca de la unidad de control y la UAL (unidad aritmetico logica).
En el R2000 (y creo que es mas o menos igual en el 3000), los registros
estan repartidos de la siguiente forma:

- 32 registros de 32 bits de proposito general para operaciones con enteros
  que se almacenan segun el criterio de Ca2 (complemento a 2).
- 32 registros de 32 bits de proposito general para operaciones con reales
  en simple precision segun el formato IEEE 754 (coma flotante).
- 16 registros de 64 bits para operaciones con reales de doble precision
  en coma flotante.
- 2 registros de 32 bits (HI y LO) que sirven para almacenar el resultado de
  las operaciones de multiplicacion y division entre otras cosas.

A los registros para operaciones con enteros se los identifica con un simbolo
$ seguido del numero de registro. Asi, si nos referimos al registro 5 lo
hacemos con $5.
A los de coma flotante en simple precision les ponemos delante un $f. En el
R2000 estos registros para operaciones con reales se encuentran en un copro
aparte.
El registro $0 SIEMPRE tiene el valor 0.

Por otra parte, ademas, tenemos una UAL de 32 bits tope cojonuda, tio ;-XX

Bueno, si alguien aun sigue leyendo esto (ya se que es muy tecnico, pero no
querreis que os explique como chusca un micro con colorcitos y ventanitas).
Aqui estamos para aprender BAJO NIVEL. Y quien no quiera que se vaya a leer
otras revistas que hablen de Visual Kaki, o de lo que sea. Solo os dire que
los de la NASA no utilizaron en los tres 486 que utilizaron para su telescopio
ningun lenguaje visual ;-o)

Bueno, prosigamos, que si pierdo el hilo esto puede llegar a ser entretenido
y todo...  ;)


$ Organizacion de la memoria $
------------------------------
En el MIPS R2000 una word equivale a 32 bits (no como en los Intel, que son
16 bits). Esto es asi porque es lo mas utilizado en el procesador: los regs
son de 32b, las intrucciones tb, etc.
Por lo tanto, la memoria tambien esta organizada en words (4 bytes).
Podemos referenciar una posicion por byte, por half o por word.
Por byte, pos eso, se dice el byte que es (0, 1, 2, ....).
Por half (1 half=16 bits=2 bytes) se hace con direcciones pares (porque vamos
de 2 en dos bytes como es logico -> 0, 2, 4, ...).
Y por ultimo, por word se hace de 4 en 4 (0, 4, 8, 12, .....).
Por lo tanto en un MIPS podemos direccionar hasta 4 Gbytes de memoria
(la oxtia !!! :). Si no os lo creeis haced el calculo: 2^32 bytes con
direcciones que van de la 0 a la 2^32 - 1.
La memoria a la que un usuario puede acceder va desde la posicion
00400000h a la 7FFFFFFFh. Ahi va un mapa pa que sea mas ilustrativo :->

----------------------------------------  0xffffffff
|                                      |
|         SISTEMA OPERATIVO            |
|                                      |
|                                      |
|______________________________________|  0x80000000
|                                      |  0x7fffffff
|          PILA                        |
|          DATOS DINAMICOS             |
|          DATOS ESTATICOS             |
|______________________________________|  0x10000000
|                                      |  0x0fffffff
|                                      |
|          CODIGO EJECUTABLE           |
|                                      |
|______________________________________|  0x00400000
|                                      |  0x003fffff
|                                      |
|          RESERVADO                   |
|                                      |
|______________________________________|  0x00000000

Respecto a lo de como se escriben los datos, puede utilizar tanto formato
Motorola como Intel. De hecho se selecciona con un jumper. Esto se hizo 
para poder comunicarse sin problemas con las demas computadoras, y porque
los ingenieros quisieron ser los mas chulos de todos (uy! creo que esto 
ultimo sobraba ;)

NOTA: en los simuladores (el SPIM, vamos) se suele utilizar solo un formato.

Bueno, y ahora ya empieza el catxondeo:

$ Juego de instrucciones $ (jejeje ahora si que os vais a dormir XDDD )
--------------------------
1. INSTRUCCIONES LOGICAS

and rd, rs, rt             xor rd, rs, rt        srl rd, rt, desp
formato: R                 formato: R            formato: R
rd <- rs and rt            rd <- rs or rt        rd <- rt >> desp

nor rd, rs, rt             sll rd, rt, desp      or rd, rs, rt
formato: R                 formato: R            formato: R
rd <- rs nor rt            rd <- rt << desp      rd <- rs or rt

las and, or, nor, etc son faciles de ver: te cogen los dos registros del
final, hacen la operacion logica que toque y te ponen el resultado en rd.
Por cierto, lo de rd, rs y rt son registros.
Tambien hay versiones de estas para valores inmediatos, poniendoles una i
al final (nori, xori, andi, ...) para en vez de poner un registro donde iria
rt poder poner un numero tu. El formato de estas ultimas es I.
Lo del formato se utiliza para pasar mnemonicos en lenguaje ensamblador a su
correspondiente codigo maquina, que ya veremos si explico.

2. INSTRUCCIONES DE CALCULADORA BARATA

add rd, rs, rt            mult rs, rt
formato: R                formato: R
rd <- rs + rt             HI y LO <- rs * rt

sub rd, rs, rt            div rs, rt
formato: R                formato: R
rd <- rs - rt             HI y LO <- rs / rt

Por supuesto existe la intruccion addi (aunque creo que la subi no exite:
corregidme si me equivoco).
Respecto a lo de mult y div, en mult, se guarda en HI la parte alta y en LO
la parte baja de los 32 bits del resultado; en div se guarda en HI el resto
y en LO el cociente (tambien os parece un poco ilogico esto a vosotros ??).

Lo de multiplicar se puede hacer de otra forma para que consuma menos ciclos
de reloj: multiplicar en binario equivale a desplazar 2 bits a la izquierda,
por lo que:
$2 << 2 equivale a $2 * 4

3. INSTRUCCIONES DE CARGA Y ALMACENAMIENTO

Pos eso, las de carga sirven para hacer la operacion memoria -> registros
y las de almacenamiento al reves (registros -> memoria).
Todas tienen formato I.

lw rt, despl(rs)         lb rt, despl(rs)       sh rt, despl(rs) 
rt <- [desp+rs]          rt <- [desp+rs]        rt -> [desp+rs]
      ( 1 word )              ( 1 byte )              ( 1 half )

lh rt, despl(rs)         sw rt, despl(rs)       sb rt, despl(rs)
rt <- [desp+rs]          rt -> [desp+rs]        rt -> [desp+rs]
      ( 1 half )               ( 1 word )             ( 1 byte )

lo de lw, lb, lh viene de load half, word y byte y lo de sX viene de 
storage. Por supuesto, la suma desp+rs tenemos que tener en cuenta que
se hace en funcion de lo de organizacion de la memoria que hemos dicho
antes, osea que si utilizais un lw no me seais cebollos y hagais que la 
suma despl+rs no sea multiplo de cuatro, porque estais cargando una word
que son 4 bytes, y teneis que direccionar un word (0, 4, 8, etc.). Lo mismo
pasa con lb, sh, y todas las demas.
A parte, tambien hay otra que la lui (load upper inmediate), que lo que hace
es cargar en la parte alta de un registro (los bits del 16..31) un valor
que le demos. La sintaxis es:
     lui rt, inmediate
     rt(0..15) <- 0
     rt(16..32) <- inmediate
(fijaros que pone los bits 0..15 a 0: esto es importante).

 * Nota: *
Normalmente, en lo de despl(rs), si hay que poner un 0 en alguno, se suele
poner el 0 en el despl y el valor en rs, ya que el valor que pongas en
despl tiene que ser de 16 bits y si pones menos pueden haber movidas de 
extension de signo (para representar un numero binario de 7 bits con el de 
12 bits equivalente, por ejemplo) y esas cosas, asi que no te arriesgues 
y hazlo asi.

4. INSTRUCCIONES DE MOVIMIENTO DE DATOS

El formato de todas estas es R.

mfhi rd          mflo rd            mthi rd             mtlo rd
rd <- HI         rd <- LO           HI <- rd            LO <- rd

5. INSTRUCCIONES DE COMPARACION

Son dos:

SET IF LESS THAN:               SET IF LESS THAN INMEDIATE:
slt rd, rs, rt                  slti rt, rs, inmediate
formato: R                      formato: I
(rs < rt) -> rd := 1            (rs < inmediate) -> rt := 1
si no rd := 0                   si no rt := 0

6. INSTRUCCIONES DE SALTO

Condicional:

        beq rs, rt, direcc       (BRANCH IF EQUAL)
        formato: I
        (rs = rt) -> va a direcc

        bne rs, rt, direcc       (BRANCH IF NOT EQUAL)
        formato: I
        (rs != rt) -> va a direcc

Incondicional:

        j direcc
        formato: J
        va a la direcc por cojones

        jal direcc
        formato: J
        va a direcc guardandose la direccion de retorno en $31

        jr rs
        formato: R
        va a la direcc contenida en rs

un ejemplo para jal (que se utiliza para llamar a procedimientos):
__start:
        jal inicio      # $31 := PC + 4  y  PC := inicio
        .......
        .......

inicio: 
        .......
        .......
.end

Como habreis podido observar se pueden utilizar nombres para que sea mas
facil referirse a las posiciones de memoria. Los comentarios van con #, que
equivale al ; de los Intel. Lo de PC es el contador de programa, que en el
MIPS es tambien un registro $, aunque no me acuerdo cual ahora. De todas
formas en el SPIM se puede poner PC y ya esta.

Bueno, y aqui dejamos las intrucciones. Por supuesto hay un monton mas, pero
a quien les interese que las busque por ahi, que haga algun articulillo,  y
que lo mande a SET  ;-D
De todas formas igual, si vamos escasos de otros contenidos en algun proximo
numero las pongo.



$ Directivas del ensamblador $
------------------------------
bueno, todas las intrucciones anteriores estan muy bien, pero sin las 
malditas directivas no podemos hacer nada: hay que indicarle al ensamblador
donde empieza el codigo, donde estan los datos y todo lo demas.
Un programa, quiero decir, el codigo ejecutable empieza con la etiqueta
__start (si, hay dos guioncillos) y el programa lo finalizamos con .end
Ejemplo:

__start:     ( a ver quien es el chulo que me dice que hace esto ;)

  .end

Para reservar memoria, al estilo de las db, dw, etc del Intel tenemos:
.space (reserva n bytes de memoria inicializandolos a 0)
.ascii (para almacenar cadenas en memoria)
.asciiz
la diferencia entre .ascii y .asciiz es que la ultima almacena la cadena, pero
terminandola con el caracter ascii 0 (el NULL ese).
por supuesto, se pueden reservar varias cadenas:
.ascii "capullo", "idiota", "aznar"
.byte, .half, .word, .float, .double guardan lo que su nombre indica.
.float guarda reales en simple precision y .double en doble
Por cierto, para indicar a partir de donde demonios se van a guardar los
datos se hace con la directiva .data
Si no se pone el .data o se pone pero sin nada a continuacion el ensamblador
asume que se quiere almacenar a partir de la primera posicion de la memoria
de datos (la 0x10000000, como indica el mapa de la memoria de antes).
Para poner instrucciones a partir de una cierta direccion se hace con
.text direcc. Pos eso.
Estaria bien que pilleis el SPIM de por ahi y pongais algunos datos y 
veais como se representan en la memoria reservada para los datos (normalmente
suele haber una ventanilla para la memoria reservada para los datos).

bueno, en vista de que esto se esta haciendo largo como una telenovela
(shit!! eso de explicar un micro no se puede hacer en un cuartito de hora)
vamos a dejar lo demas para un proximo articulo. En concreto queda por 
explicar lo de la pila, algunas pseudoinstrucciones y poner algun ejemplo,
que si no esto queda muy como de manual de referencia askeroso.

Espero que os haya gustado medianamente. Si es asi podeis escribirme a mi
buzon de correo y me lo decis, que tengo la sensacion de que nadie me lee
cuando escribo; por que sera ;) ????

En fin: dudas, criticas (constructivas), etc, a <yboy@latinmail.com>

CONTINUARA..... (o que pensabas????? ;)