MIPS (procesador)
# MIPS (procesador)

Con el nombre de MIPS (siglas de Microprocessor without Interlocked Pipeline Stages) se conoce a toda una familia de microprocesadores de arquitectura RISC desarrollados por MIPS Technologies.

Los diseños del MIPS son utilizados en la línea de productos informáticos de SGI; en muchos sistemas embebidos; en dispositivos para Windows CE; routers Cisco; y videoconsolas como la Nintendo 64 o las Sony PlayStation, PlayStation 2 y PlayStation Portable. Más recientemente, la NASA usó uno de ellos en la sonda New Horizons

Las primeras arquitecturas MIPS fueron fsfs en 32 bits (generalmente rutas de datos y registros de 32 bits de ancho), si bien versiones posteriores fueron implementadas en 64 bits. Existen cinco revisiones compatibles hacia atrás del conjunto de instrucciones del MIPS, llamadas MIPS I, MIPS II, MIPS III, MIPS IV y MIPS 32/64. En la última de ellas, la MIPS 32/64 Release 2, se define a mayores un conjunto de control de registros. Así mismo, están disponibles varias "extensiones", tales como la MIPS-3D, consistente en un simple conjunto de instrucciones SIMD en coma flotante dedicadas a tareas 3D comunes, la MDMX(MaDMaX) compuesta por un conjunto más extenso de instrucciones SIMD enteras que utilizan los registros de coma flotante de 64 bits, la MIPS16 que añade compresión al flujo de instrucciones para hacer que los programas ocupen menos espacio (presuntamente como respuesta a la tecnología de compresión Thumb de la arquitectura ARM) o la reciente MIPS MT que añade funcionalidades multithreading similares a la tecnología HyperThreading de los procesadores Intel Pentium 4.

Debido a que los diseñadores crearon un conjunto de instrucciones tan claro, los cursos sobre arquitectura de computadores en universidades y escuelas técnicas a menudo se basan en la arquitectura MIPS. El diseño de la familia de CPU's MIPS influiría de manera importante en otras arquitecturas RISC posteriores como los DEC Alpha.

## Historia

En 1981, un equipo liderado por John L. Hennessy en la Universidad de Stanford comenzó a trabajar en lo que se convertiría en el primer procesador MIPS. La idea básica era mejorar drásticamente el rendimiento mediante el uso de la segmentación, una técnica que ya era entonces muy conocida pero también difícil de implementar. Su funcionamiento puede resumirse en que la ejecución de una instrucción es dividida en varias etapas, comenzando la "etapa 1" de una instrucción antes de que haya finalizado la ejecución de la instrucción anterior. En contraste, los diseños tradicionales esperaban la finalización por completo de una instrucción antes de pasar a la siguiente, de modo que grandes áreas de la CPU permanecían inactivas mientras el proceso continuaba. Además, la frecuencia de reloj de toda la CPU venía dictada por la latencia del ciclo completo, en lugar de por el llamado camino crítico, latencia de la etapa de segmentación que más tarda en completarse.

Otra de las grandes barreras a superar por la segmentación era la necesidad de introducir bloqueos para poder asegurarse de que las instrucciones que necesitan varios ciclos de reloj para completarse dejan de cargar datos desde los registros de segmentación. Estos bloqueos pueden durar cantidades de tiempo considerables, y suponían una gran barrera a mejoras de velocidad posteriores. Por ello, uno de los principales aspectos del diseño del MIPS fue el marcarse como objetivo que todas las subfases (incluyendo el acceso a memoria) de todas las instrucciones tardasen un único ciclo en completarse, dejando así de ser necesarios los bloqueos, y permitiendo un rendimiento de un solo ciclo.

Aunque esta idea de diseño eliminó numerosas instrucciones útiles, destacando el hecho de que la multiplicación y la división necesitarían varias instrucciones, en conjunto se sabía que el rendimiento general del sistema sería drásticamente mejorado al poder funcionar los chips a frecuencias mucho mayores. Este ascenso de la velocidad sería difícil con la intervención de los bloqueos, pues el tiempo necesario es función del tamaño del chip y de la frecuencia de reloj: añadir el hardware necesario para evitarlos reduciría notablemente la velocidad del sistema.

La eliminación de estas instrucciones se convirtió en un tema polémico. Muchos observadores afirmaron que ese diseño (y los procesadores RISC en general) nunca superaría sus ambiciosas expectativas ("Si uno sencillamente sustituye la instrucción compleja de multiplicación por una simple serie de sumas, ¿dónde se produce el incremento de velocidad?"). Este análisis tan simplista ignoraba el hecho de que la velocidad del diseño residía en la segmentación, no en las instrucciones.

En 1984 Hennessy se convenció del futuro potencial comercial del diseño, dejando Stanford para formar MIPS Computer Systems. La empresa presentó su primer diseño, el R2000, en 1985, siendo mejorado con el R3000 de 1988. Estas CPU's de 32 bits fueron la base de la compañía durante los 80, y fueron empleadas principalmente en algunas series de workstations de SGI. Estos diseños comerciales se diferenciaron de los de investigación académica de Stanford en aspectos como la implementación de la mayoría de los bloqueos con hardware y el proporcionar instrucciones completas para la multiplicación y la división, entre otros.

En 1991 MIPS presentó su primer procesador de 64 bits, el R4000. Sin embargo, MIPS tuvo dificultades financieras en su lanzamiento al mercado. El diseño era tan importante para SGI, entonces uno de los pocos grandes clientes de MIPS, que en 1992 compró sin recelo alguno la compañía para evitar que se perdiera el diseño. Como subsidiaria de SGI, la compañía pasó a llamarse MIPS Technologies.

A principios de los 90 MIPS comenzó a otorgar licencias de sus diseños a terceros. Esto probó con justo éxito la simplicidad del núcleo, algo que le permitía ser empleado en numerosas aplicaciones que anteriormente utilizaban diseños CISC mucho menos capaces y de precio y número de puertas similares (comentar que ambas magnitudes están estrechamente relacionadas; el precio de una CPU está generalmente relacionado con el número de puertas y pines externos). Sun Microsystems intentó subirse al carro otorgando licencias de su núcleo SPARC, pero ni llegó a rozar el éxito del MIPS. A finales de los 90 MIPS tenía un caballo de batalla en los procesadores integrados, y en 1997 fue entregado el procesador MIPS 48 millones, convirtiéndose en la primera CPU RISC en desbancar a la famosa familia 68k de Motorola. La familia MIPS tuvo tanto éxito que SGI relanzó a MIPS Technologies en 1998. Más de la mitad de los ingresos de MIPS actualmente proceden de las concesiones de licencias, mientras que gran parte del resto procede de contratos de diseño de núcleos para ser fabricados por terceros.

En 1999 MIPS consolidó su sistema de licencias alrededor de dos diseños básicos, el MIPS32 de 32 bits y el MIPS64 de 64 bits. NEC, Toshiba y SiByte (posteriormente adquirida por Broadcom) obtuvieron licencias para el MIPS64 tan pronto como este procesador fue anunciado; a estas empresas les siguieron otras como Philips, LSI Logic e IDT. Los éxitos se sucedieron, y actualmente los núcleos MIPS son uno de los pesos pesados del mercado de dispositivos como los computadoras de mano o decodificadores y sintonizadoras de TV. Un indicio de su éxito es el hecho de que Freescale (filial de Motorola) utilice procesadores MIPS en sus aparatos, en lugar de otros propios basados en el PowerPC.

Desde que la arquitectura MIPS es licenciable, ha atraído a numerosas compañías jóvenes a lo largo de los años. Una de las primeras nuevas compañías en diseñar procesadores MIPS fue Quantum Effect Devices. El equipo de diseño de MIPS encargado del R4300 fundó SandCraft, que diseñó el R5432 para NEC y posteriormente el SR7100, uno de los primeros procesadores basados en ejecución fuera de orden para sistemas embebidos. El equipo original de diseño del DEC StrongARM finalmente se dividió en dos compañías MIPS: SiByte, fabricante del SB-1250, uno de los primeros sistemas de chip único de alto rendimiento basados en el MIPS; y Alchemy Semiconductor (más tarde comprada por AMD), que fabricaba el sistema de chip único Au-1000 para aplicaciones poco exigentes. Lexra utilizó arquitectura pseudo-MIPS y añadió extensiones DSP para el mercado de los chips de audio y soporte multithreading para el mercado de redes. Debido a que Lexra no era concesionaria de ninguna licencia MIPS, dos pleitos fueron abiertos entre ambas empresas. El primero se resolvió rápidamente al prometer Lexra no seguir anunciando sus procesadores como MIPS-compatibles. El segundo fue largo y dañó los intereses de ambas compañías, terminando con la concesión por parte de MIPS de una licencia gratuita a Lexra, así como el pago de una gran cantidad de dinero.

## Familia de CPU's

El primer modelo de CPU comercial de MIPS, el R2000, fue anunciado en 1985. Añadía instrucciones multiciclo para la multiplicación y la división en una unidad independiente integrada en el procesador. Asimismo se añadieron instrucciones para enviar los resultados de esta unidad al núcleo; las cuales necesitaban bloqueos.

El R2000 podía ser iniciado tanto en formato big-endian como little-endian. Tenía 32 registros de propósito general de 32 bits, pero no contaba con un registro de estado, lo que suponía un considerable cuello de botella. Este problema lo compartía con el AMD 29000 y el DEC Alpha. Al contrario que otros registros, el contador de programa no es directamente accesible.

El R2000 además soportaba hasta cuatro co-procesadores, uno de los cuales estaba integrado en la CPU principal para el manejo de excepciones e interrupciones, mientras que los otros tres estaban destinados a otros usos. Una opción era añadir la unidad de punto flotante R2010, que contaba con 32 registros de 32 bits que podían ser empleados como tales para manejar números en simple precisión o bien como 16 registros de 64 bits en doble precisión.

El R3000 sucedería al R2000 en 1988, añadiendo una caché de 32 kB (pronto aumentada a 64 kB) para instrucciones y datos, junto con el soporte de "coherencia caché" para el uso multiprocesador. Mientras hubo defectos en el soporte multiprocesador del R3000, MIPS se las siguió arreglando para que formase parte de varios diseños exitosos de multiprocesador. El R3000 también incluía una unidad de manejo de memoria (MMU) integrada, característica común entre los procesadores del momento. El R3000 fue el primer diseño exitoso de MIPS en el mercado, y finalmente fueron fabricadas más de 1 millón de unidades. El R3000A, utilizado en la extremadamente exitosa Sony PlayStation, fue una versión acelerada hasta los 40 MHz. Al igual que el R2000, el R3000 fue emparejado con la FPU R3010. Pacemips fabricó el R3400 e IDT el R3500, siendo ambos modelos procesadores R3000s con la FPU R3010 en un único chip. El Toshiba R3900 fue el primer sistema de chip único para los primeros ordenadores de mano con Windows CE.

En la serie R4000, presentada en 1991, se extendió el juego de instrucciones del MIPS para constituir una auténtica arquitectura de 64 bits y se movió la FPU al mismo circuito para crear un sistema de chip único, operando a una velocidad de reloj radicalmente superior (inicialmente 100 MHz). Sin embargo, para poder alcanzar tal frecuencia las cachés fueron reducidas a 8 kB cada una, siendo necesarios tres ciclos de reloj para acceder a ellas. Las altas frecuencias de trabajo fueron alcanzadas gracias a la técnica de segmentación profunda (llamada entonces super-segmentación). Tras el R4000 nació un gran número de versiones mejoradas, incluyendo la R4400 de 1993 con cachés de 16 kB, operaciones de 64 bits sin apenas errores y un controlador para otra caché externa (L2) de 1 MB.

MIPS, actualmente una división de SGI llamada MTI, diseñó la versión de bajo coste R4200, y posteriormente la aún más barata R4300, consistente en un R4200 con bus externo de 32 bits. La Nintendo 64 usa una CPU NEC VR4300 basada en el MIPS de bajo coste R4300i.

Quantum Effect Devices (QED), una compañía aparte fundada por antiguos ingenieros de MIPS, diseñaron el R4600 "Orion", el R4700 "Orion", el R4650 y el R5000. Mientras que el R4000 aumentó la frecuencia a cambio de reducir capacidad de caché, los diseños de QED destacaron por las grandes cachés accesibles en solo dos ciclos de reloj y por el uso eficiente del área de silicio. Los R4600 y R4700 fueron utilizados en las versiones de bajo coste de las estaciones de trabajo SGI Indy así como en los primeros enrutadores Cisco basados en el MIPS, aquellos de las series 36x0 y 7x00. El R4650 fue empleado en los aparatos originales de WebTV (ahora Microsoft TV). La FPU R5000 trabajaba de forma más eficiente y flexible con números en simple precisión que la R4000, y como resultado, con similar hardware gráfico, las SGI Indy que montaban la FPU R5000 ofrecían mucho mejor rendimiento gráfico que las que contaban con la R4400. SGI rebautizó a las viejas tarjetas gráficas que incorporaron la R5000 para remarcar la mejora. QED posteriormente diseñó las familias RM7000 y RM9000 para sistemas embebidos como redes e impresoras láser. QED fue adquirida por el fabricante de semiconductores PMC-Sierra en agosto de 2000, siendo esta la última compañía en invertir en la arquitectura MIPS.

El R8000 (1994) fue el primer diseño MIPS superescalar, capaz de ejecutar dos operaciones de ALU y otras dos de memoria en cada ciclo de reloj. El diseño se plasmó en seis chips: una unidad entera (con dos cachés de 16 KB, una para instrucciones y otra L1 de datos), una unidad de punto flotante, tres RAM de caché secundaria totalmente personalizables (dos para accesos a caché secundaria y otra para bus), y un controlador de caché ASIC. El diseño tenía dos unidades segmentadas de suma-multiplicación en doble precisión, las cuales recibían el flujo de datos de la caché secundaria externa de 4 MB. El R8000 fue montado en los servidores SGI Power Challenge a mediados de los 90 y posteriormente en las estaciones de trabajo Power Indigo2. Su rendimiento limitado en operaciones enteras y su elevado coste lo hicieron impopular entre la mayoría de los usuarios, si bien el buen rendimiento de su FPU fue aprovechado por los usuarios científicos; el R8000 estuvo apenas un año en el mercado.

En 1995, fue lanzado el R10000. Este procesador era un diseño de chip único, con mayor velocidad de reloj que el R8000, y mayores cachés primarias de 32 kB para instrucciones y datos. Era también superescalar, pero su gran innovación fue ser "out-of-order". Aún con una FPU más simple, la vasta mejora en las operaciones con enteros, su menor precio y la mayor densidad hicieron del R10000 el preferido por muchos clientes.

Los diseños más recientes se basan en el R10000. El R12000 ha sido fabricado con tecnología mejorada para comprimir el chip y operar a mayor velocidad de reloj. La revisión R14000 permitía mayores frecuencias, soporte adicional para DDR SRAM en el chip externo de caché y un FSB de 200 MHz para un mejor transferencia. Las últimas versiones fueron llamadas R16000 y R16000A, caracterizándose por una mayor velocidad de reloj, caché L1 adicional y chips de menor tamaño en comparación con los anteriores.

Note: Estas especificaciones hacen referencia a las configuraciones más comunes. Existen variaciones, sobre todo en las cachés de nivel 2.

## Aplicaciones

Entre los fabricantes de estaciones de trabajo basadas en procesadores MIPS destacan SGI, MIPS Computer Systems, Inc., Olivetti, Siemens-Nixdorf, Acer, Digital Equipment Corporation, NEC y DeskStation. Varios sistemas operativos fueron portados a la arquitectura, ejemplos de ello son el SGI IRIX, Microsoft Windows NT (aunque el soporte para MIPS finalizó con el lanzamiento de Windows NT 4.0) y Windows CE, Linux, BSD, UNIX System V, SINIX, MIPS Computer Systems RISC/os, entre otros.

Sin embargo, el uso del MIPS como procesador principal de estaciones de trabajo ha caído, y SGI ha anunciado sus planes de cesar el desarrollo de iteraciones de alto rendimiento de la arquitectura MIPS en favor de procesadores basados en la tecnología Intel IA64 (véase la sección "Otros modelos y planes futuros").

Por otra parte, el uso de microprocesadores MIPS en sistemas embebidos es probable que se mantenga gracias al bajo consumo de energía y características térmicas de las implementaciones integradas, así como a la gran disponibilidad de herramientas de desarrollo y de expertos conocedores de la arquitectura.

## Otros modelos y planes futuros

Otro miembro de la familia MIPS es el R6000, una implementación ECL de la arquitectura MIPS fabricada por Bipolar Integrated Technology. El R6000 introdujo el juego de instrucciones MIPS II. Su arquitectura TLB y de caché son diferentes del resto de miembros de la familia MIPS. El R6000 no proporcionó los resultados esperados, y aunque fue empleado en algunas máquinas Control Data, rápidamente desapareció del mercado de los mainstream. El PMC-Sierra RM7000 fue una versión del R5000 con una caché integrada de nivel 2 de 256 kB y un controlador para una caché opcional de tercer nivel. Diseñado en un principio para sistemas embebidos como los procesadores gráficos SGI y varias soluciones de redes de Cisco. El nombre R9000 nunca fue utilizado.

SGI intentó una vez migrar de la plataforma MIPS a la Intel Itanium, habiendo terminado su desarrollo con el R10000. Los grandes retrasos en la presentación del Itanium hicieron que el número de procesadores basados en MIPS instalados continuó creciendo. En 1999 quedó claro que el proceso de desarrollo había sido cerrado demasiado pronto, y resultado de ello son las versiones R14000 y R16000. SGI tanteó la posibilidad de añadir una FPU más compleja al estilo de la del R8000 en las últimas iteraciones, así como la de lanzar un procesador de doble núcleo, pero los problemas financieros de la empresa y el uso oficial y soportado de la emulación QuickTransit para ejecutar binarios IRIX sobre Altix provocaron el cese definitivo del desarrollo de hardware IRIX/MIPS.

### Loongson

Loongson es una familia de microprocesadores diseñados por la Academia China de Ciencias. La microarquitectura interna de los microprocesadores Loongson fue diseñado de forma independiente por los chinos. Las primeras implementaciones de la familia carecía de cuatro instrucciones, patentadas por MIPS Technologies. En junio de 2009, ICT obtuvo licencias MIPS32 y MIPS64 directamente de MIPS Technologies.

A partir de 2006, una serie de empresas empezaron a comercializar una serie de hardware con el procesador Loongson, incluyendo nettops y netbooks con un bajo consumo.

## Núcleos

En los últimos años gran parte de la tecnología empleada en las distintas generaciones MIPS ha sido ofrecida como diseños de "IP-cores" (bloques de construcción) para sistemas embebidos. Se ofertan los núcleos básicos de 32 y 64 bits, conocidos respectivamente como 4K y 5K respectivamente, y con licencias MIPS32 y MIPS64. Estos núcleos pueden ser combinados con unidades añadidas tales como FPUs, sistemas SIMD, dispositivos de E/S, etc.

Los núcleos MIPS han sido comercialmente exitosos, siendo empleados actualmente en muchas aplicaciones industriales y de consumo. Pueden encontrarse en los más modernos enrutadores Cisco, TP-Link y Linksys , cablemódems y módems ADSL, tarjetas inteligentes, controladoras de impresoras láser, decodificadores de TV, robots, ordenadores de mano, Sony PlayStation 2 y Sony PlayStation Portable.

En móviles y PDA's, sin embargo, el núcleo MIPS fue incapaz de desbancar a su competidor de arquitectura ARM.

## Programación y emulación

Existe un simulador MIPS R2000/R3000 totalmente libre llamado SPIM (MIPS al revés) compatible con varios sistemas operativos (específicamente Unix o GNU/Linux; Mac OS X; MS Windows 95, 98, NT, 2000, XP y DOS) ideado para el aprendizaje de la programación en ensamblador MIPS y de los conceptos generales del ensamblador RISC: http://www.cs.wisc.edu/~larus/spim.html

Otro simulador popular es MARS (MIPS Assembler and Runtime Simulator), un IDE (Integrated Design Environment) para programar MIPS en lenguaje Assembly. MARS es un entorno de desarrollo ligero e interactivo, escrito en Java y compatible con muchas plataformas, cuyo propósito es su uso en el nivel educativo.

Un emulador MIPS más completo pertenece al proyecto GXemul (anteriormente conocido como Proyecto mips64emul), el cual no solo emula las diferentes versiones de los microprocesadores MIPS III y superiores (desde el R4000 al R10000), sino también sistemas enteros que utilicen esos procesadores. Por ejemplo, GXemul puede emular tanto una DECstation con un procesador MIPS R4400 (y arrancar en Ultrix) como un SGI O2 con CPU MIPS R10000 (si bien la capacidad de correr Irix es limitada), entre otros, así como también diferentes framebuffers y controladoras SCSI.

El software QEMU es capaz de emular también, entre muchas otras, la arquitectura MIPS y MIPSel, así como ejecutar GNU/Linux en la máquina emulada.

El simulador CREATOR es portable y permite aprender diversos lenguajes ensamblador de diferentes procesadores (CREATOR dispone de ejemplos con una implementación de las instrucciones MIPS32 y RISC-V).

El simulador WepSIM puede usarse desde un navegador Web. Es un simulador educativo para programar en MIPS que dispone de distintos ejemplos que usan una implementación de instrucciones MIPS de forma microprogramada. WepSIM facilita aprender diversos aspectos de cómo funciona una CPU (microprogramación, interrupciones, llamadas al sistema, excepciones, etc.).

## Resumen de llamadas al sistema

Realizar una llamada al sistema por parte de un programa es solicitar un servicio al sistema operativo, habitualmente para mostrar por pantalla información o leer del teclado información.

Antes de realizar la solicitud del servicio mediante la instrucción syscall, se ha de indicar el código asociado al servicio en el registro $v0 e indicar en los registros asociados a dicho servicio los valores de información con los que operar.

A continuación en la siguiente tabla se muestran ejemplos de los servicios más usados en los simuladores SPIM, MARS, CREATOR o WepSIM.

Ejemplos de llamadas al sistema usadas en SPIM :

| Servicio | Código trampa | Entrada | Salida | Notas |
| - | - | - | - | - |
| print_int | $v0=1 | $a0= entero a imprimir | Imprime $a0 en la salida estándar | |
| print_float | $v0=2 | $f12= float a imprimir | Imprime $f12 en la salida estándar | |
| print_double | $v0=3 | $f12= double a imprimir | Imprime $f12 en la salida estándar | |
| print_string | $v0=4 | $a0= dirección del primer carácter | Imprime la cadena de caracterer en la salida estándar | |
| read_int | $v0=5 | | Lee en $v0 un entero de la entrada estándar | |
| read_float | $v0=6 | | Lee en $v0 un float de la entrada estándar | |
| read_double | $v0=7 | | Lee en $v0 un double de la entrada estándar | |
| read_string | $v0=8 | $a0 = dirección del buffer, $a1= longitud del buffer | Lee en el buffer de la entrada estándar | |
| sbrk | $v0=9 | $a0= número necesario de bytes | Deja en $v0 la dirección de memoria reservada | Reserva memoria del montón o heap |
| exit | $v0=10 | | | Finaliza la ejecución |

## Resumen del juego de instrucciones del R3000

Las instrucciones se dividen en tres tipos: R, I y J. Todas las instrucciones empiezan con un código de operación de 6 bits. Además del código de operación, en las instrucciones tipo R se especifican tres registros, un campo de tamaño de desplazamiento ('shamt') y otro para el código de función; Las tipo I especifican dos registros y un valor inmediato de 16 bits; en las tipo J al código de operación le siguen 26 bits de dirección destino de salto.

Nombre de los registros, número, uso y convenciones de llamada (si es guardado en subrutina llamada):

Registros :

| Nombre | Número | Uso | Preservado en subrutina llamada |
| - | - | - | - |
| $zero | $0 | constante entera 0 | sí |
| $at | $1 | temporal del ensamblador | no |
| $v0–$v1 | $2–$3 | Valores de retorno de funciones y evaluación de expresiones | no |
| $a0–$a3 | $4–$7 | Paso argumentos a subrutinas | no |
| $t0–$t7 | $8–$15 | Temporales | no |
| $s0–$s7 | $16–$23 | Temporales salvados | sí |
| $t8–$t9 | $24–$25 | Temporales | no |
| $k0–$k1 | $26–$27 | Reservados para el núcleo del S.O. | no |
| $gp | $28 | puntero global | sí |
| $sp | $29 | puntero de pila | sí |
| $fp | $30 | puntero de marco de pila | sí |
| $ra | $31 | dirección de retorno | no |

Los registros preservados durante una llamada son aquellos que (por convenio) no serán modificados por una llamada de sistema o a una subrutina (que implemente en ensamblador un procedimiento o función). Por ejemplo, los registros $s_ deben ser almacenados en la pila por el procedimiento que los necesita (subrutina llamada), siendo siempre incrementados en constantes $sp y $fp, para ser después decrementados una vez finalizado el procedimiento (se marca como disponible la memoria reservada). Por el contrario, $ra es modificado automáticamente tras una llamada a una función normal (cualquiera que utilice la instrucción jal), y los registros $t_ deben ser salvados por la subrutina llamante antes de llamar a cualquier función (por si el programa necesita los valores contenidos en dichos registros tras la ejecución de la subrutina ).

### Instrucciones reales

Existen una serie de instrucciones que poseen implementación hardware directa, en oposición a las pseudoinstrucciones que son traducidas a varias instrucciones reales antes de ser ensambladas.

Los siguientes son los tres posibles formatos de instrucción:

| Tipo | -31-                Formato (bits)                -0- | -31-                Formato (bits)                -0- | -31-                Formato (bits)                -0- | -31-                Formato (bits)                -0- | -31-                Formato (bits)                -0- | -31-                Formato (bits)                -0- |
| - | - | - | - | - | - | - |
| R | codop (6) | rs (5) | rt (5) | rd (5) | shamt (5) | codfunc (6) |
| I | codop (6) | rs (5) | rt (5) | inmediato/desplazamiento (16) | inmediato/desplazamiento (16) | inmediato/desplazamiento (16) |
| J | codop (6) | dirección (26) | dirección (26) | dirección (26) | dirección (26) | dirección (26) |

* CONST denota una constante ("inmediata").
* A partir de ahora, los números de registros son simples ejemplos, pudiendo ser empleados otros en su lugar.
* Todas las instrucciones que siguen son nativas.
* Los códigos de operación y función se dan en hexadecimal.

| Categoría | Nombre | Sintaxis de la instrucción | Significado | Formato/codop/codfunc | Formato/codop/codfunc | Formato/codop/codfunc | Notas |
| - | - | - | - | - | - | - | - |
| Aritméticas | Suma | add $1,$2,$3 | $1 = $2 + $3 (con signo) | R | 0 | $20_{16}$ | suma dos registros |
| Aritméticas | Suma sin signo | addu $1,$2,$3 | $1 = $2 + $3 (sin signo) | R | 0 | $21_{16}$ |
| Aritméticas | Resta | sub $1,$2,$3 | $1 = $2 - $3 (con signo) | R | 0 | $22_{16}$ | resta dos registros |
| Aritméticas | Suma inmediata | addi $1,$2,CONST | $1 = $2 + CONST (con signo) | I | $8_{16}$ | | empleado para sumar constantes (y también para copiar de un registro a otro "addi $1, $2, 0") |
| Aritméticas | Suma inmediata sin signo | addiu $1,$2,CONST | $1 = $2 + CONST (sin signo) | I | $9_{16}$ | |
| Aritméticas | Multiplicación | mult $1,$2 | LO = (($1 * $2) << 32) >> 32; HI = ($1 * $2) >> 32; | R | 0 | $18_{16}$ | Multiplica dos registros y guarda el resultado de 64 bits en dos puntos especiales de la memoria - LO y HI. De forma alternativa, uno puede decir que el resultado de esta operación es: (int HI,int LO) = (64 bits) $1 * $2 . |
| Aritméticas | División | div $1, $2 | LO = $1 / $2 HI = $1 % $2 | R | | | Divide dos registros y guarda el resultado entero de 32 bits en LO y el resto en HI. |
| Transferencia de datos | Carga de dirección | la $1, Etiqueta | $1 = Dirección de memoria | I | | | Carga la dirección de memoria de una etiqueta. |
| Transferencia de datos | Carga de palabra | lw $1,CONST($2) | $1 = Memoria[$s2 + CONST] | I | $23_{16}$ | | Carga la palabra almacenada desde ($s2+CONST) en adelante (3 bytes más). |
| Transferencia de datos | Carga de media palabra | lh $1,CONST($2) | $1 = Memoria[$s2 + CONST] | I | $25_{16}$ | | Carga la media palabra almacenada desde ($s2+CONST) en adelante (1 byte más). |
| Transferencia de datos | Carga de byte | lb $1,CONST($2) | $1 = Memoria[$s2 + CONST] | I | | | Carga el byte almacenado en ($s2+CONST). |
| Transferencia de datos | Almacenamiento de palabra | sw $1,CONST($2) | Memoria[$s2 + CONST] = $1 | I | | | Almacena una palabra en ($s2+CONST) y los siguientes 3 bytes. El orden de los operandos es una gran fuente de confusiones. |
| Transferencia de datos | Almacenamiento de media palabra | sh $1,CONST($2) | Memoria[$s2 + CONST] = $1 | I | | | Almacena la primera mitad de un registro (media palabra) en ($s2+CONST) y el byte siguiente. |
| Transferencia de datos | Almacenamiento de byte | sb $1,CONST($2) | Memoria[$s2 + CONST] = $1 | I | | | Almacena el primer byte de un registro en ($s2+CONST). |
| Transferencia de datos | Carga del inmediato superior | lui $1,CONST | $1 = CONST << 16 | I | | | Carga un operando inmediato de 16 bits en los 16 bits del registro especificado. El valor máximo de la constante es $2^{16}-1$ |
| Transferencia de datos | Mover desde "high" | mfhi $1 | $1 = HI | R | | | Mueve un valor de HI al registro. No se debe emplear una instrucción de multiplicación o división entre dos instrucciones mfhi (esta acción no está definida debido a la segmentación del MIPS). |
| Transferencia de datos | Mover desde "low" | mflo $1 | $1 = LO | R | 0 | $12_{16}$ | Mueve un valor de LO al registro. No se debe emplear una instrucción de multiplicación o división entre dos instrucciones mflo (esta acción no está definida debido a la segmentación del MIPS) |
| Lógicas | And | and $1,$2,$3 | $1 = $2 & $3 | R | | | And bit a bit |
| Lógicas | And con inmediato | andi $1,$2,CONST | $1 = $2 & CONST | I | | | |
| Lógicas | Or | or $1,$2,$3 | $1 = $2 | $3 | R | | | Or bit a bit |
| Lógicas | Or con inmediato | ori $1,$2,CONST | $1 = $2 | CONST | I | | | |
| Lógicas | Or exclusivo | xor $1,$2,$3 | $1 = $2 ^ $3 | R | | | |
| Lógicas | Nor | nor $1,$2,$3 | $1 = ~($2 | $3) | R | | | Nor bit a bit |
| Lógicas | Inicializar si menor que | slt $1,$2,$3 | $1 = ($2 < $3) | R | | | Comprueba si un registro es menor que el otro. |
| Lógicas | Inicializar si menor que con inmediato | slti $1,$2,CONST | $1 = ($2 < CONST) | I | | | Comprueba si un registro es menor que una constante. |
| Desplazamiento de bits | Desplazamiento lógico a la izquierda | sll $1,$2,CONST | $1 = $2 << CONST | R | | | Desplaza el registro CONST bits a la izquierda (lo multiplica por $2^{CONST}$) |
| Desplazamiento de bits | Desplazamiento lógico a la derecha | srl $1,$2,CONST | $1 = $2 >> CONST | R | | | Desplaza el registro CONST bits a la derecha rellenado con ceros (divide entre $2^{CONST}$). Nótese que esta instrucción solo funciona como división de un número en complemento a 2 si dicho número es positivo. |
| Desplazamiento de bits | Desplazamiento aritmético a la derecha | sra $1,$2,CONST | $\$1=\$2>>CONST+\$ ${\bigg{\bigg\sum _{n=1}^{CONST}2^{31-n}{\bigg )}\cdot \$2>>31{\bigg )}$ | R | | | Desplaza el registro CONST bits rellenando con el bit de signo correspondiente (divide un número en complemento a 2 entre $2^{CONST}$) |
| Saltos condicionales | Salto si igual | beq $1,$2,CONST | if ($1 == $2) go to PC+4+CONST | I | $04_{16}$ | | Salta a la instrucción situada en la dirección especificada si ambos registros son iguales. |
| Saltos condicionales | Salto si no igual | bne $1,$2,CONST | if ($1 != $2) go to PC+4+CONST | I | $05_{16}$ | | Salta a la instrucción situada en la dirección especificada si ambos registros no son iguales. |
| Salto incondicional | Salto | j CONST | goto address CONST | J | | | Salta de forma incondicional a la instrucción almacenada en la dirección especificada. |
| Salto incondicional | Salto a registro | jr $1 | goto address $1 | R | | | Salta a la dirección almacenada en el registro especificado. |
| Salto incondicional | Salto y enlace | jal CONST | $31 = PC + 4; goto CONST | J | | | Utilizada en las llamadas a subrutinas. Guarda en $31 la dirección de retorno, a la que se vuelve con jr $31 |

NOTA: En las instrucciones de saltos y bifurcaciones, CONST puede sustituirse por una etiqueta existente en cualquier parte del código.

Las pseudoinstrucciones son traducidas en varias instrucciones reales antes de ser ensambladas.

| Nombre | Sintaxis de la instrucción | Traducción a instrucciones reales | Significado |
| - | - | - | - |
| Saltar si mayor que | bgt $rs,$rt,Label | slt $at,$rt,$rs; bne $at,$zero,Label | if(R[rs]>R[rt]) PC=Label |
| Saltar si menor que | blt $rs,$rt,Label | slt $at,$rs,$rt; bne $at,$zero,Label | if(R[rs]<R[rt]) PC=Label |
| Saltar si mayor o igual que | bge $rs,$rt,Label | slt $at,$rs,$rt; beq $at,$zero,Label | if(R[rs]>=R[rt]) PC=Label |
| Saltar si menor o igual que | ble $rs,$rt,Label | slt $at,$rt,$rs; beq $at,$zero,Label | if(R[rs]<=R[rt]) PC=Label |
| Saltar si igual que | beq $rs, $rt, Label | beq $rs, $rt, Label | if(R[rs]==R[rt]) PC=Label |
| Saltar si igual a cero | beqz $rs,Label | beq $rs,$zero,Label | if(R[rs]==0) PC=Label |
| Saltar si mayor que (sin signo) | bgtu $rs,$rt,Label | sltu $at,$rt,$rs; bne $at,$zero,Label | if(R[rs]>R[rt]) PC=Label |
| Saltar si mayor que cero | bgtz $rs,Label | slt $at,$zero,$rs; bne $at,$zero,Label | if(R[rs]>0) PC=Label |

### Otras instrucciones

Estas instrucciones podrían clasificarse tanto entre las "reales" como entre las "pseudoinstrucciones".

**Instrucciones lógicas comunes bit a bit**

| addiu $1,$2,100 | $1 = $2 + 100 (suma sin signo con inmediato) |
| - | - |
| addu $1,$2,$3 | $1 = $2 + $3 (suma sin signo) |
| div $1,$2 | HI = $1 % $2 ; LO = $1 / $2 |
| subu $1,$2,$3 | $1 = $2 - $3 (resta sin signo) |

**Instrucciones de transferencia de memoria a registro**

| lbu $1,100($2) | Carga un byte sin signo |
| - | - |
| lhu $1,100($2) | Carga media palabra sin signo |
| lwcz $1,100($2) | Carga una palabra al coprocesador "z" ("z" es el número del coprocesador) |

Véase que no existe la instrucción "carga del inmediato inferior", ya que este trabajo puede realizarse mediante una addi (suma con inmediato) o una ori (or con inmediato) con el registro $0 (cuyo valor siempre es cero). Por ejemplo, tanto addi $1, $0, 100 como ori $1, $0, 100 cargan el número decimal 100 en el registro $1.

**Instrucciones de transferencia de registro a memoria**

| swcz $1,100($2) | Almacena una palabra desde el coprocesador "z" ("z" es el número del coprocesador). |
| - | - |

**Instrucciones de movimiento de registro a registro**

| mfcz $1,$c1 | Mueve un valor del registro $1 del coprocesador al registro $1 del procesador principal ("z" es el número del coprocesador) |
| - | - |
| mtcz $1,$c1 | Mueve un valor del registro $1 del procesador principal al registro $1 del coprocesador ("z" es el número del coprocesador) |
| mov.d $fp1,$fp3 | Mueve un valor en doble precisión del registro $3 de la FPU al registro de punto flotante $1 del procesador principal |
| mov.s $fp1,$fp3 | Mueve un valor en simple precisión del registro $3 de la FPU al registro de punto flotante $1 del procesador principal |

(los valores en doble precisión usan dos registros adyacentes de la FPU)

Una operación con constantes con signo difiere de una sin signo en que no lanza excepciones. La resta de una constante puede ser realizada como la suma de su negación.

### Otras instrucciones importantes

* nop (no operation) (de código máquina 0x00000000 e interpretada por la CPU como sll $0,$0,0)
* break (finaliza el programa, se emplea en tiempo de depuración)
* syscall (llamadas al sistema)
* algunas instrucciones relacionadas con la FPU
* instrucciones virtuales, descompuestas por el ensamblador en instrucciones nativas

## Referencia de instrucciones y registros del MIPS R4000

Esta es la lista de referencia de instrucciones y registros del MIPS R4000, con 32 registros de 32 bits. Este procesador se encuentra específicamente en la consola PlayStation Portable de Sony Computer Entertainment

add addu addi addiu and andi divu mult multu div nor or ori sll sllv sra srav srl srlv sub subu xor xori lhi llo slt sltu slti sltiu beq bgtz blez bne j jal jalr jr la li lb lbu lh lhu lw sb sh sw mfhi mflo mthi mtlo trape

$at $v0 $v1 $a0 $a1 $a2 $a3 $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $s0 $s1 $s2 $s3 $s4 $s5 $s6 $s7 $t8 $t9 $k0 $k1 $gp $sp $fp $ra

