RISC-V: instruções e codificação

Operações RV32, formatos R I S B U J, imediatos e pseudo-instruções.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

lw a0,8(t0) reúne três decisões: ler uma word, usar t0 como base e somar 8 bytes ao endereço. A instrução de 32 bits codifica a operação, os registos e esse imediato; aqui usamos os formatos de 32 bits de RV32I, sem a extensão de instruções comprimidas.

Aritmética e lógica

A sintaxe add rd,rs1,rs2 significa rd←rs1+rs2rd\leftarrow rs1+rs2. sub, and, or e xor seguem a mesma ordem. O destino pode coincidir com uma fonte: a operação lê os valores antigos antes de escrever.

addi rd,rs1,imm usa um imediato de 12 bits com sinal, de −2048-2048 a 2047. O imediato é estendido com sinal também em andi, ori e xori. Por exemplo, xori t0,t0,-1 inverte todos os bits; os bits 111111111111, ou FFF em hexadecimal, representam -1 neste campo. Escreve -1 no programa para indicar esse valor com sinal, em vez de assumir que qualquer assembler aceita a escrita positiva 4095 como imediato de 12 bits.

sll desloca para a esquerda; srl desloca para a direita introduzindo zeros; sra repete o sinal. Em RV32, as versões por registo usam os 5 bits inferiores da quantidade de deslocamento. slli, srli, srai usam uma quantidade de 0 a 31.

slt e sltu escrevem 1 se a primeira fonte for menor que a segunda, com ou sem sinal. As somas mantêm os 32 bits inferiores e não lançam uma exceção por overflow inteiro.

A extensão M acrescenta mul para a metade baixa do produto, e mulh, mulhu, mulhsu para a metade alta com fontes respetivamente sinal/sinal, sem sinal/sem sinal e sinal/sem sinal. div divide com sinal truncando para zero; rem dá o resto. divu e remu usam valores sem sinal. srai de -3 por uma posição dá -2, enquanto dividir -3 por 2 dá -1.

Casos limite da divisão

Na extensão M, divisão por zero não gera uma exceção inteira: o quociente fica com todos os bits a 1 e o resto é o dividendo. No caso com sinal −231/(−1)-2^{31}/(-1), o quociente conserva −231-2^{31} e o resto é 0. O programa deve testar estes casos quando o contrato exige um resultado matemático representável.

Loads e stores

lw rd,d(rs1) lê uma word em rs1+drs1+d. sw rs2,d(rs1) escreve uma word nesse endereço. O deslocamento é em bytes, com 12 bits com sinal. lb e lh estendem o sinal; lbu e lhu estendem com zeros. sb e sh escrevem só os 8 ou 16 bits inferiores.

Não há um registo de destino num store. Em sw a0,12(s0), a0 é o dado e s0 é a base. Trocar estes papéis altera tanto o endereço como o valor escrito.

Saltos

beq e bne comparam igualdade; blt e bge comparam com sinal, enquanto bltu e bgeu comparam sem sinal. Se a condição for falsa, o PC segue para PC+4; se for verdadeira, vai para PC da instrução + deslocamento.

O formato B representa um deslocamento par, em bytes, de -4096 a 4094. O bit 0 é implícito. Sem a extensão comprimida, as instruções continuam alinhadas a 4 bytes; um destino que só seja múltiplo de 2 pode ser inválido. Usa etiquetas em código para o assembler calcular o deslocamento.

jal rd,etiqueta guarda PC+4 em rd e salta para PC+d. O formato J permite deslocamentos pares de −220-2^{20} a 220−22^{20}-2 bytes. jalr rd,d(rs1) guarda PC+4 e salta para (rs1+d)&∼1(rs1+d)\mathbin{\&}\sim1, limpando o bit 0. O valor de rs1 é o antigo, mesmo se rs1=rd.

Campos dos formatos

Lê esta tabela do bit 31 para o bit 0. op ocupa 7 bits, cada registo 5, f3 3 e f7 7.

FormatoCampos do bit 31 ao 0
Rf7, rs2, rs1, f3, rd, op
Iimm[11:0], rs1, f3, rd, op
Simm[11:5], rs2, rs1, f3, imm[4:0], op
Bimm[12], imm[10:5], rs2, rs1, f3, imm[4:1], imm[11], op
Uimm[31:12], rd, op
Jimm[20], imm[10:1], imm[11], imm[19:12], rd, op

Os índices de imm são os bits do deslocamento reconstruído, não posições consecutivas na instrução. S e B não têm rd; U e J não têm rs1 nem rs2.

Codificar passo a passo

Para add t0,t1,t2, os registos são x5, x6, x7. add usa op=0110011, f3=000, f7=0000000, com

0000000 | 00111 | 00110 | 000 | 00101 | 0110011

O código é 0x007302B3. sub muda f7 para 0100000; and usa f3=111 e f7=0000000. Uma operação não fica identificada apenas por f3.

Para lw a0,-12(s0), usa x10 e x8, op=0000011, f3=010. O imediato de 12 bits é 4096−12=4084=FF4164096-12=4084=\mathrm{FF4}_{16}, com

111111110100 | 01000 | 010 | 01010 | 0000011

Dá 0xFF442503. No store sw a0,12(s0), reparte 000000001100 em 0000000 e 01100; o código é 0x00A42623. Reconstrói S juntando imm[11:5] e imm[4:0] antes de estender o sinal; reconstrói B juntando imm[12],imm[11],imm[10:5],imm[4:1] e o bit 0 implícito. Para um branch de −8-8, os campos B são imm[12]=1,imm[11]=1,imm[10:5]=111111,imm[4:1]=1100.

Para beq x5,x6 com destino 16 bytes à frente, imm[4:1]=1000 e os outros bits de imm são 0. Dá 0x00628863. O imediato B é repartido pela palavra:

Bits do deslocamentoPara +16Posições na instrução
imm[12]031
imm[10:5]00000030:25
imm[4:1]100011:8
imm[11]07
imm[0]0Implícito, não guardado

Para descodificar, repõe a ordem imm[12], imm[11], imm[10:5], imm[4:1], 0 e estende o sinal. O resultado já está em bytes. Não coloques o inteiro 16 num campo contínuo de 12 bits nem multipliques o valor reconstruído novamente por 2.

Para jal ra com destino 8 bytes à frente, rd=x1, op=1101111. O deslocamento 8 tem imm[10:1]=0000000100; os restantes campos do imediato são 0:

0 | 0000000100 | 0 | 00000000 | 00001 | 1101111

A palavra é 0x008000EF. O salto usa PC+8, mas ra recebe PC+4. O endereço de destino e o endereço de retorno têm funções diferentes.

Constantes e pseudo-instruções

lui rd,u coloca u nos 20 bits superiores e zeros nos 12 inferiores. auipc rd,u soma esse valor ao PC atual. Para construir 0x12345ABC, a parte baixa ABC seria um imediato negativo, -1348. Usa lui t0,0x12346 e addi t0,t0,-1348: a soma dá o valor desejado.

Pseudo-instruções são conveniências do assembler. mv rd,rs é addi rd,rs,0; not usa xori com -1; neg usa sub rd,zero,rs; j é jal zero; ret é jalr zero,0(ra). li, la e call podem expandir em mais de uma instrução. Para contar ciclos ou calcular endereços, conta as instruções máquina emitidas, não só as linhas do ficheiro.

Exercícios

Descodificar os campos

Descodifica 0x407302B3 usando o formato R. Identifica os três registos e a operação.

Pista

Separa op, rd, f3, rs1, rs2, f7.

Mais uma pista

É o exemplo de add com f7 alterado.

Solução

op=0x33, rd=5, f3=0, rs1=6, rs2=7, f7=0x20. Isto é sub x5,x6,x7, ou sub t0,t1,t2. f3=0 sozinho não distingue add de sub; f7 é necessário.

Confere a tua resposta:

  • sub x5,x6,x7.
  • Identifica op=33 e f7=20 para distinguir de add.

Erros frequentes

Não interpretes f7=0x20 como um imediato.

Voltar à explicação
Imediato dividido de um store

Codifica sw x10,-4(x8). Mostra as duas partes do imediato S e o hexadecimal.

Pista

O imediato de 12 bits para -4 é 0xFFC.

Mais uma pista

imm[11:5]=1111111 e imm[4:0]=11100.

Solução

O formato é 1111111 | 01010 | 01000 | 010 | 11100 | 0100011. O código é 0xFEA42E23. x10 entra no campo rs2 e x8 no rs1. Não há rd neste formato.

Confere a tua resposta:

  • Imediato FFC repartido em 1111111 e 11100.
  • Código FEA42E23 com rs2=x10 e rs1=x8.

Erros frequentes

Não escrevas o imediato S como um único campo à esquerda de rs1.

Voltar à explicação
Destino relativo ao branch

beq x5,x6,alvo está em 0x00400030 e alvo em 0x00400020. Determina o deslocamento em bytes, os quatro campos de imediato B e o código hexadecimal. Usa opcode=1100011 e funct3=000. Indica o PC seguinte se a comparação for falsa.

Pista

Subtrai o endereço da própria instrução, porque o deslocamento é relativo ao PC do branch.

Mais uma pista

O deslocamento é -16, representado em 13 bits com bit 0 implícito.

Solução

O deslocamento é 0x00400020-0x00400030=-16 bytes. Em 13 bits, -16 é 1 1111 1111 0000. Assim imm[12]=1, imm[10:5]=111111, imm[4:1]=1000 e imm[11]=1. Com rs2=x6 e rs1=x5, a palavra é:

1 | 111111 | 00110 | 00101 | 000 | 1000 | 1 | 1100011

O código é 0xFE6288E3. Se x5 e x6 diferirem, PC passa a 0x00400034. Se forem iguais, vai para 0x00400020. O deslocamento é relativo ao PC do branch; os campos omitem apenas o bit 0, não dois bits.

Confere a tua resposta:

  • Deslocamento -16 bytes e campos B 1,111111,1000,1.
  • Código FE6288E3 para beq x5,x6.
  • Destino relativo ao PC da instrução; se não tomado, PC=00400034.

Erros frequentes

Usar PC+4 daria -20 e outro código.

Voltar à explicação
A metade baixa tem sinal

Escreve duas instruções reais para obter 0x7ABCDEFF em t0. Justifica o imediato negativo.

Pista

A metade baixa de 12 bits é EFF.

Mais uma pista

EFF como imediato de 12 bits vale -257.

Solução

Usa lui t0,0x7ABCE e addi t0,t0,-257. O primeiro produz 0x7ABCE000; subtrair 0x101 dá 0x7ABCDEFF. O upper foi aumentado para compensar a extensão de sinal da parte baixa.

Confere a tua resposta:

  • lui com 7ABCE e addi com -257.
  • Justifica a compensação da extensão de sinal.

Erros frequentes

lui 0x7ABCD seguido do imediato EFF com sinal produziria uma palavra 0x1000 abaixo do desejado.

Voltar à explicação
Fonte e destino iguais

Antes de jalr ra,0(ra), ra=0x00400081 e a instrução está em 0x00400020. Quais são PC e ra depois?

Pista

O alvo usa o ra antigo e limpa o bit 0.

Solução

O alvo é 0x00400080, depois de limpar o bit 0 de 0x00400081. ra passa a 0x00400024, PC da instrução+4. O novo ra não é a base do salto. O alvo está alinhado a 4 neste exemplo.

Confere a tua resposta:

  • PC=00400080 e ra=00400024.
  • Usa a fonte antiga e limpa o bit zero.

Erros frequentes

Não calcules o destino com o endereço de retorno recém-escrito.

Voltar à explicação
Um salto para trás

Codifica jal x1 com destino 4 bytes antes da instrução atual, em RV32I. Dá os campos J, o hexadecimal e os efeitos quando o PC inicial é 0x00400020.

Pista

Representa −4 em 21 bits, incluindo o bit 0 que não é guardado.

Mais uma pista

O bit 0 é 0; os bits 10:1 acabam em 10.

Solução

−4 tem os 21 bits 1 1111 1111 1111 1111 1100. O formato J reúne imm[20]=1, imm[10:1]=1111111110, imm[11]=1 e imm[19:12]=11111111. Com rd=00001 e op=1101111, dá 0xFFDFF0EF. O destino é PC−4=0x0040001C; ra recebe PC+4=0x00400024. O bit 0 implícito é reconstruído na execução.

Confere a tua resposta:

  • Campos 1 | 1111111110 | 1 | 11111111, rd=00001.
  • Código FFDFF0EF; destino 0040001C e ra 00400024.

Erros frequentes

Não confundas a ordem dos campos J com a ordem natural dos bits do deslocamento, porque o formato espalha imm pela instrução. O retorno não é o destino do salto.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.