Itinerario RISC-V

RISC-V: de la palabra binaria al pipeline

Las tres herramientas RISC-V del sitio responden a tres preguntas distintas sobre la misma instrucción: cómo está codificada, qué hace al ejecutarse y cuánto tarda cuando se solapa con otras. Aquí las recorremos con un bucle de tres líneas.
li   t0, 3
loop:
  addi t0, t0, -1
  bnez t0, loop

El bucle carga 3 en t0 y resta 1 hasta que t0 vale 0. Parece trivial, pero contiene los tres temas: una instrucción con inmediato negativo, un salto condicional hacia atrás y una dependencia entre instrucciones consecutivas.

1. Codificación: bnez es un bne con desplazamiento negativo

bnez no existe en la ISA: es una pseudoinstrucción que el ensamblador traduce a bne t0, zero, loop. Como loop está 4 bytes antes del salto, el desplazamiento es −4 y la palabra resultante es 0xFE029EE3. En el formato B el inmediato está repartido en cuatro trozos y su bit 0 no se guarda, porque los destinos siempre son pares:

0xFE029EE3 · B-Type
CampoBitsBinarioSignificado
imm[12][31]1trozo del inmediato
imm[10:5][30:25]111111trozo del inmediato
rs2[24:20]00000registro x0 (zero)
rs1[19:15]00101registro x5 (t0)
funct3[14:12]001selecciona la operación dentro del grupo
imm[4:1][11:8]1110trozo del inmediato
imm[11][7]1trozo del inmediato
opcode[6:0]1100011grupo BRANCH
imm-4 (0xFFFFFFFC)inmediato reconstruido (con signo)
Instrucciónbne t0, zero, -4

Uniendo imm[12], imm[11], imm[10:5] e imm[4:1] y añadiendo el 0 final sale 1 1 111111 1110 0 = −4. Ábrelo en el decodificador.

Los seis formatos de un vistazo

FormatoCampos (bit 31 → bit 0)Se usa para
Rfunct7 · rs2 · rs1 · funct3 · rd · opcodeoperaciones entre registros (add, sub, and, sll…)
Iimm[11:0] · rs1 · funct3 · rd · opcodeoperaciones con inmediato, cargas y jalr
Simm[11:5] · rs2 · rs1 · funct3 · imm[4:0] · opcodealmacenamientos (sw, sh, sb)
Bimm[12|10:5] · rs2 · rs1 · funct3 · imm[4:1|11] · opcodesaltos condicionales (beq, bne, blt…)
Uimm[31:12] · rd · opcodelui y auipc
Jimm[20|10:1|11|19:12] · rd · opcodejal

Fíjate en que rs1, rs2 y rd ocupan siempre las mismas posiciones. Es una decisión de diseño de RISC-V: el hardware puede empezar a leer los registros antes de saber qué instrucción es, a cambio de repartir los bits del inmediato.

2. Ejecución: seguir el PC

Al ejecutar, cada instrucción cambia registros y el PC. bnez no escribe ningún registro: solo decide si el PC vuelve a loop o sigue. El cuerpo se ejecuta 3 veces, así que se ejecutan 1 + 3 × 2 = 7 instrucciones y t0 termina en 0. En el depurador, pulsa «Paso» y observa cómo el PC salta de 0x00000008 a 0x00000004 dos veces.

3. Pipeline: lo que cuesta un salto

En un pipeline de 5 etapas el salto no se resuelve hasta EX. Para entonces ya se han buscado las dos instrucciones siguientes, y si el salto se toma hay que descartarlas. El simulador trata todos los saltos como tomados, así que el diagrama muestra exactamente esa penalización de 2 ciclos. La dependencia de bne con addi (t0) no cuesta nada gracias al forwarding.

Etapa12345678910
IFI0I1I2I3I2I3————
ID—I0I1I2FLUSHI2I3———
EX——I0I1FLUSHFLUSHI2I3——
MEM———I0I1FLUSHFLUSHI2I3—
WB————I0I1FLUSHFLUSHI2I3
Con forwarding: 10 ciclos, 0 burbujas, 2 instrucciones descartadas. I0 = addi t0, t0, -1 · I1 = bne t0, zero, loop · I2 = addi a0, a0, 1 · I3 = addi a1, a1, 1

Abre este ejemplo en el simulador de pipeline.

Itinerario recomendado

  1. Guía: cómo decodificar una instrucción RV32I y los ejercicios de decodificación y formatos.
  2. Guía: del código máquina al ensamblador, que traduce una rutina completa con saltos y etiquetas.
  3. Depurador y los ejercicios de traza de registros y bucles.
  4. Guía: el pipeline de 5 etapas y riesgos RAW, forwarding y burbujas, con el ejercicio de carga-uso.

Referencias