Instrucciones básicas de RISC-V addi y lui (generan un número inmediato mayor, incluido el caso especial de expansión de signo negativo)

Estas dos instrucciones son instrucciones de números enteros en la arquitectura RISC-V. Sus funciones y formatos son los siguientes:

  • El nombre completo de la instrucción lui es Load Upper Immediate, su función es cargar un valor inmediato de 20 bits en los 20 bits superiores del registro, y los 12 bits inferiores son 0. Su formato es:

    a rd, imm

    Entre ellos, rd es el registro de destino e imm es un número inmediato de 20 bits. Por ejemplo, lui x1, 0x12345 cargará 0x12345000 en el registro x1.

  • El nombre completo de la instrucción addi es Agregar Inmediato, su función es sumar el valor de un registro a un número inmediato de 12 bits y almacenar el resultado en otro registro. Su formato es:

    addi rd, rs1, imm

    Entre ellos, rd es el registro de destino, rs1 es el registro de origen e imm es un número inmediato de 12 bits. Por ejemplo, addi x2, x1, 0x678 agregará el valor del registro x1 a 0x678 y almacenará el resultado en el registro x2.

Estas dos instrucciones se pueden combinar para generar un valor inmediato superior a 20 bits. Por ejemplo, si desea generar un valor inmediato de 32 bits 0x12345678, puede hacer esto:

lui x3, 0x12345
addi x3, x3, 0x678

Los datos inmediatos de la instrucción lui y la instrucción addi deben ser de 12 y 20 bits. Esto se debe a que uno de los principios de diseño del conjunto de instrucciones RISC-V son las instrucciones de longitud fija, lo que significa que cada instrucción tiene 32 bits. Para representar códigos de operación, números de registro y valores inmediatos en una instrucción de 32 bits, se debe asignar una cierta cantidad de bits a cada parte. Tanto la instrucción lui como la instrucción addi pertenecen a instrucciones de tipo I y su formato es el siguiente:

31:20 19:15 14:12 11:7 6:0
soy rs1 función3 tercero código de operación

Se puede ver que la parte imm ocupa 12 bits, las partes rs1 y rd ocupan 5 bits cada una, y las partes funct3 y opcode ocupan 3 y 7 bits respectivamente. Esto suma exactamente 32 bits. Por lo tanto, los datos inmediatos de la instrucción lui y la instrucción addi no pueden exceder los 12 bits.

Sin embargo, el valor inmediato de la instrucción lui es en realidad 20 bits, porque se desplazará 12 bits a la izquierda y se cargará en los 20 bits superiores del registro. Por lo tanto, se puede considerar que la instrucción lui divide un valor inmediato de 20 bits en dos partes de 10 bits, luego coloca los 10 bits superiores en los 10 bits superiores de imm y los 10 bits inferiores en los 10 bits inferiores de imm. Por ejemplo, si desea cargar 0x12345 en los 20 bits superiores del registro, puede escribir:

de x1, 0x12345

Esta instrucción es en realidad equivalente a:

de x1, 0x012_345

Entre ellos, 0x012 son los 10 bits altos y 0x345 son los 10 bits bajos. Se combinan en un valor inmediato de 12 bits 0x12345, se desplazan 12 bits a la izquierda y se cargan en el registro x1.

Tanto la instrucción lui como la addi se pueden utilizar para generar valores inmediatos, pero tienen algunas limitaciones:

  • La instrucción lui puede cargar un valor inmediato de 20 bits en los 20 bits superiores del registro y los 12 bits inferiores son 0.
  • La instrucción addi agrega un valor inmediato de 12 bits al valor de un registro y almacena el resultado en otro registro.
  • El valor inmediato de 12 bits tiene signo, lo que significa que puede representar un número positivo o negativo. Si es un número negativo, entonces su bit más alto (bit 11) es 1 y se ampliará con signo durante la operación de suma, lo que significa que sus 20 bits superiores se convertirán en 1.

Por lo tanto, si desea generar un valor inmediato mayor a 20 bits, debe combinar las instrucciones lui y addi. Por ejemplo, si desea generar un número inmediato de 32 bits 0xFEEDA987, puede hacer esto:

  • Utilice la instrucción lui para cargar 0xFEEDB en los 20 bits superiores del registro s2, y los 12 bits inferiores son 0. De esta forma, el valor del registro s2 pasa a ser 0xFEEDB000.
  • Utilice la instrucción addi para agregar 0x987 al valor del registro s2 y almacene el resultado en el registro s2. De esta forma, el valor del registro s2 pasa a ser 0xFEEDA987.

Tenga en cuenta que hay dos lugares que requieren especial atención:

  • ¿Por qué la instrucción lui carga 0xFEEDB en lugar de 0xFEEDA? Debido a que 0x987 es un número negativo, el signo se extenderá a 0xFFFFF987 durante la suma. Si la instrucción lui carga 0xFEEDA, el resultado después de la operación de suma será 0xFEED9987, no el 0xFEEDA987 que queremos. Por lo tanto, necesitamos aumentar en 1 el valor inmediato cargado por la instrucción lui, para que se pueda obtener el resultado correcto después de la operación de suma.
  • ¿Por qué 0x987 es un número negativo? Debido a que es un número de 12 bits con signo, su bit más alto (bit 11) es 1. En notación en complemento a dos, si el bit más alto de un número es 1, entonces es un número negativo. Para encontrar su valor absoluto, debes negarlo y sumar 1. Por ejemplo, 0x987 se invierte para obtener 0xF678 y se suma 1 para obtener 0xF679. Entonces el número negativo representado por 0x987 es −1657.

Aquí, explique el signo negativo con más detalle (es decir, el bit 11 del número inmediato además, el bit máximo es 1, que es el caso donde el signo negativo se expande para producir un número negativo mayor)

Supongamos que queremos generar un valor inmediato de 32 bits 0x12345678. Podemos usar las instrucciones lui y addi para combinarlo, de la siguiente manera:

lui s0,0x12345 # 把0x12345加载到s0寄存器的高20位,低12位为0

addi s0,s0,0x678 # 把0x678加到s0寄存器的值上,并把结果存入s0寄存器

Esto nos dará el resultado que queremos, 0x12345678. Esto se debe a que 0x678 es un número positivo, al que no se le extenderá el signo durante la suma, lo que significa que sus 20 bits superiores son todos 0. Entonces, el resultado después de la operación de suma es la simple suma de los dos números.

Sin embargo, si queremos generar un número inmediato de 32 bits 0x1234F678, no podemos utilizar el método anterior. Debido a que 0xF678 es un número negativo, se extenderá el signo durante la operación de suma, lo que significa que sus 20 bits superiores se convertirán en 1. Entonces, si usamos las instrucciones lui y addi para combinarlo, queda de la siguiente manera:

lui s0,0x1234F # 把0x1234F加载到s0寄存器的高20位,低12位为0

addi s0,s0,0xF678 # 把0xF678加到s0寄存器的值上,并把结果存入s0寄存器

Entonces el resultado que obtenemos no es el que queremos. Esto se debe a que el resultado de la operación de suma es:

s0 = 0x1234F000 + 0xFFFFF678 = 0x1234E678

Como puede ver, el resultado es 1000 menos de lo que queríamos. Esto se debe a que la extensión de signos equivale a convertir un número negativo en un número negativo mayor. Por lo tanto, necesitamos aumentar en 1 el valor inmediato cargado por la instrucción lui, para compensar el impacto de la extensión de signos. Es decir, deberíamos escribir así:

lui s0,0x12350 # 把0x12350加载到s0寄存器的高20位,低12位为0

addi s0,s0,0xF678 # 把0xF678加到s0寄存器的值上,并把结果存入s0寄存器

De esta manera podremos obtener los resultados que queremos. Esto se debe a que el resultado de la operación de suma es:

s0 = 0x12350000 + 0xFFFFF678 = 0x1234F678

Tenga en cuenta que aquí debe comprender el significado del código de complemento. El código de complemento de un número negativo es un código binario que se puede sumar a su número opuesto mediante desbordamiento, de modo que el resultado del cálculo en la computadora se convierte en 0, por lo que + Se utilizó 1 operación en el lugar anterior.

Para obtener una introducción más detallada al código de complemento, consulte una breve revisión de los conocimientos básicos de la arquitectura de la computadora y el código de complemento original code_Guan Ergou, ¡apúrate y ponte a trabajar! Blog-Blog de CSDN

Supongo que te gusta

Origin blog.csdn.net/qq_52505851/article/details/132085930
Recomendado
Clasificación