resueltos modos mip minimips memoria lenguaje instrucciones ensamblador ejercicios ejemplos direccionamiento assembler assembly mips

assembly - modos - ¿Cuál es la diferencia entre la rama incondicional y el salto incondicional(instrucciones en MIPS)?



mip s (4)

Como ya se mencionó, la rama tiene menos bits, un rango más corto y es relativa. Jump tiene más bits y es absoluto.

Toma este ejemplo

b l0 nop beq $0,$1,l1 nop j l2 nop l0: .word 0,0 l1: .word 0,0 l2: .word 0,0

y obtienes esto

00000000 <l0-0x1c>: 0: 10000006 b 1c <l0> 4: 00000000 nop 8: 10010006 beq zero,at,24 <l1> c: 00000000 nop 10: 0800000b j 2c <l2> 14: 00000000 nop 18: 00000000 nop 0000001c <l0>: ... 00000024 <l1>: ... 0000002c <l2>: ...

ahora lo que las otras respuestas pueden no haber mencionado es que la rama incondicional está codificada, al menos por el ensamblador gnu, como una rama si es igual, con el mismo registro. No hay una rama incondicional en mips, hay una rama si es igual y una rama si no es igual a lo que puedo decir.

Usted ve arriba el salto usa un 0xB que es la dirección de la palabra, 0xB * 4 = 0x2C la dirección del destino, donde los condicionales usan el direccionamiento relativo pc + (signed_offset * 4) donde pc = instruction_address + 4; O tome instruction_address + 4 + (signed_offset * 4) para obtener la dirección de destino.

Usar el alias b para la bifurcación en lugar de j para el salto creará un código independiente de la posición. Jump no tendrá que volver a enlazarse si te mueves, para saltos cercanos probablemente sea mejor usar una rama en lugar de saltar aunque sea un alias. Si eres un purista, entonces puedes usar la instrucción real beq $ 0, $ 0, etiqueta o elegir cualquier registro beq $ 4, $ 4, etiqueta. registrarse 0 siendo especial y rápido puede ser la mejor opción.

Puede buscar Wikipedia o un breve resumen para los estudiantes . Todo el mundo dice que hay dos instrucciones para lo mismo. Pero nadie dice por qué?


Las ramas permiten condiciones. Pero permitir las condiciones toma más bits en la instrucción. Por lo tanto, la dirección de una rama es solo de 2 ^ 16 bits y solo le permite ramificar 2 ^ 15 - 1 instrucciones hacia atrás o 2 ^ 15 instrucciones hacia adelante.

Un salto es incondicional y los bits salvados al omitir la condición se pueden usar para la dirección. Un salto permite una dirección de 26 bits y, por lo tanto, puede saltar mucho más en el código que una rama. A expensas de no ser condicional.


Un salto y una rama incondicional, en MIPS, no son lo mismo.

Tanto las instrucciones de derivación como las de salto escriben datos en el registro del contador de programas para que, en el siguiente ciclo de recuperación, se obtenga una instrucción diferente en lugar de la siguiente instrucción en línea en la memoria del programa. En ese sentido, llevan a cabo el mismo tipo de operación.

Donde difieren es que las ramas son condicionales, solo cambian la siguiente instrucción que se ejecutará si se cumple una condición determinada. Esto se puede ilustrar por la diferencia en el código de ejecución en una sentencia if o llamando a una función.

if (a == 0) { a = 1 } setAtoOne()

La instrucción if salta a la instrucción para establecer a = 1 solo si a == 0 . La función saltará a esa instrucción independientemente.

En este caso, estamos hablando de una rama donde la condición siempre es verdadera. Es solo otra forma de escribir

beq $zero, $zero, (int)offset

$ cero siempre es igual a $ cero, por lo que siempre se ramifica al desplazamiento especificado. Es como esto si la declaración

if (true) { a = 1 }

Hay otra diferencia entre las instrucciones de derivación y salto. Las instrucciones de salto especifican una dirección absoluta en la que se configurará la PC, mientras que las instrucciones de salto compensan la dirección en el contador de programa.

PC = 32-bit address # Jump PC += 16-bits lower

En realidad, esto no es estrictamente cierto. Escribimos el ensamblado con direcciones y desviaciones absolutas, pero tanto en saltos como en ramas se compila con un desplazamiento. Esta es la razón por la que no puede saltar ni ramificarse en ningún lugar de la memoria, espere utilizar el salto para registrar la instrucción jr . Esto se debe a un diseño fundamental de MIPS, instrucciones de una palabra de longitud fija.

Todas las instrucciones MIPS son de 1 palabra (es decir, 4 bytes / 32 bits) de largo. Contienen una identificación para la instrucción (llamada op-code) que es de 6 bits junto con otra información necesaria para ejecutar la instrucción. Esta puede ser la identificación de registros o valores ''inmediatos'', básicamente enteros codificados en la instrucción.

Cada byte en memoria en MIPS tiene una dirección entre 0x00000000 - 0xFFFFFFFF . Para llegar a uno de esos bytes, necesitamos especificar la dirección. Si tuviéramos la suerte de almacenar la dirección en un registro, simplemente jr y usar la dirección ya almacenada en el registro. Sin embargo, no lo somos.

Esto se vuelve problemático, solo tenemos 32 bits para nuestras instrucciones y necesitaríamos todos esos bits para especificar la dirección en ese rango. También tuvimos que renunciar a 6 bits para ser utilizados por el procesador para identificar las instrucciones. Ahora nos quedan 26 bits.

Lo que es peor es que cuando ramificamos, necesitamos 10 bits adicionales para especificar los dos registros que estamos comparando para nuestra condición. La solución es usar compensaciones.

Digamos que estamos en la dirección 0x12345678 y estamos ejecutando un salto incondicional a la siguiente dirección en la memoria j 0x1234567c . Este es el código de ensamblaje y mostraré cómo se traduce esto en código de máquina y se ejecuta.

Primero engañamos un poco. Sabemos que las instrucciones son una palabra (4 bytes) y en MIPS se especifica que deben estar dentro del límite de palabras. Esto significa que todas las instrucciones tienen direcciones separadas por 4 bytes, lo que significa que siempre terminan en 00 en representación binaria. Genial, podemos afeitar esos dos bits sin sentido. También nos afeitamos de los primeros 6, pero no se preocupe, los recuperaremos más tarde.

jump 0001 0010 0011 0100 0101 0110 0111 1100 jump 0001 0010 0011 0100 0101 0110 0111 1100 0000 1000 1000 1101 0001 0101 1001 1111 #in machine code # jump op = 0000 10 Cuando ejecutamos esto tomamos

00 1000 1101 0001 0101 1001 1111 0000 0000 1000 1101 0001 0101 1001 1111 # extend >> 6 0000 0010 0011 0100 0101 0110 0111 1100 # << 2 Entonces nosotros Y la PC (donde estamos ejecutando) y 0xf0000000

0001 0010 0011 0100 0101 0110 0111 1000 1111 0000 0000 0000 0000 0000 0000 0000 AND 0001 0000 0000 0000 0000 0000 0000 0000

Sabemos tomar el resultado de esto y O con nuestro número entero de instrucción

0001 0000 0000 0000 0000 0000 0000 0000 0000 0010 0011 0100 0101 0110 0111 1100 OR 0001 0010 0011 0100 0101 0110 0111 1100

Que es 0x1234567c en Hex y hacia donde queremos ir, ahora 0x1234567c allí. Es por eso que no puede saltar más allá de 256MB (2 ^ 28 bits) de su instrucción actual (a menos que salte al valor de un registro jr )

La misma idea básica se aplica a las ramas, excepto que ahora también tiene los 2 registros comparados (que requieren 10 bits), por lo que solo tiene 16 bits que puede usar para compensar, por lo que no puede saltar tan lejos con las ramas.

En general, esto está bien porque generalmente utilizamos ramas dentro de un procedimiento, para implementar bucles y llevar a cabo asignaciones condicionales.

Todo esto es una consecuencia del diseño de la arquitectura MIPS. Hubiera sido posible tener instrucciones donde la única diferencia entre ramas y saltos hubiera sido los aspectos condicionales y donde una rama ''incondicional'' se hubiera comportado igual que un salto incondicional.


Las ramas ( b ) usan un desplazamiento relativo de PC mientras que los saltos ( j ) usan direcciones absolutas. La distinción es importante para el código independiente de posición. Además, solo los saltos se pueden usar para la transferencia de control indirecto ( jr , utilizando un valor de registro).