# LEGv8: instruções

Formatos R, D, CB e B, acessos à memória, saltos condicionais e procedimentos.

Página: https://resumos.rgo.pt/cadeiras/fsc/legv8-instrucoes/

Cada instrução LEGv8 ocupa 4 bytes, ou seja, 32 bits. O formato, a posição dos campos dentro desses 32 bits, depende da família da instrução. Há quatro famílias nesta cadeira: R, D, CB e B.

## Instruções do tipo R

As instruções do tipo R fazem contas entre registos: `ADD`, `SUB`, `AND` e `ORR` são os exemplos. O formato divide-se assim, do bit 31 ao bit 0:

```
31        21 20    16 15    10 9     5 4      0
| OPCODE    | Rm      | SHAMT   | Rn     | Rd    |
```

`Rn` é o primeiro operando, `Rm` o segundo, `Rd` o destino e `SHAMT` a quantidade de deslocamento (quase sempre `000000`, isto é, sem deslocar). O campo `ALUOp` da unidade de controlo vale `10` para este tipo, a dizer à ALU que a operação vem do campo de função da instrução.

Um exemplo: `ADD X2, X3, X4` soma `X3` com `X4` e guarda em `X2`. Todos os operandos são registos; não há memória envolvida.

Codifica agora `ADD X0, X1, X2` campo a campo. O opcode do `ADD` é `10001011000` (11 bits), `Rm` é `X2 = 00010`, `SHAMT` é `000000`, `Rn` é `X1 = 00001` e `Rd` é `X0 = 00000`:

![Barra de 32 bits da instrução ADD X0, X1, X2 dividida em cinco campos à escala: opcode com 10001011000, Rm com 00010, SHAMT com 000000, Rn com 00001 e Rd com 00000.](https://resumos.rgo.pt/cadeiras/fsc/legv8-instrucoes/figura-1.svg)

Confere as contas: $11 + 5 + 6 + 5 + 5 = 32$ bits, e cada número de registo ocupa exatamente os 5 bits do seu campo. É este o exercício que cai em prova: do nome da instrução aos 32 bits, sem saltar campos.

## Instruções do tipo D

As instruções do tipo D acedem à memória: `LDUR` (ler) e `STUR` (escrever). O formato é:

```
31        21 20         12 11 10 9  8 9     5 4      0
| OPCODE    | OFFSET      | 00    | Rn     | Rt    |
```

O endereço acedido calcula-se como `Rn + OFFSET`, com o OFFSET em complemento para dois. A ALU, nestas instruções, efetua sempre uma adição (`ALUOp = 00`). `LDUR X0, [X1, #8]` lê a _doubleword_ que está 8 bytes acima do endereço em `X1` e guarda-a em `X0`. `STUR X0, [X1, #8]` faz o inverso.

## Saltos condicionais e incondicionais

As instruções de salto condicional (tipo CB), como `CBZ` (_compare and branch if zero_), testam um registo e saltam se ele for zero:

```
23        5 4      0
| ADDRESS   | Rt    |
```

O novo valor do PC é `PC + ADDRESS × 4`, porque cada instrução ocupa 4 bytes e o campo guarda o deslocamento em unidades de instruções[1](https://resumos.rgo.pt/cadeiras/fsc/legv8-instrucoes/#user-content-fn-unidades). O `ALUOp` vale `01` e o registo `Rt` é o registo comparado.

Confirma a conta do salto com um programa curto: com `PC = 100` e `ADDRESS = 12`, o destino é `148`:

```python
pc = 100
address = 12
print(pc + address * 4)
```

O salto incondicional `B` tem só o campo de endereço e faz sempre `PC + ADDRESS × 4`. A instrução `BL` (salto com ligação) faz o mesmo e ainda guarda em X30 (LR) o endereço da instrução seguinte, para o procedimento saber para onde regressar. É por isso que o LR existe.

## Procedimentos

Um procedimento **leaf** não chama mais ninguém e pode viver só nos registos. Um procedimento **non-leaf** invoca outros procedimentos e precisa da pilha: antes de cada chamada, guarda na pilha os registos que o chamado pode estragar (incluindo o LR) e o seu FP; no regresso, repõe tudo pela ordem inversa.

Segue uma chamada com atenção aos endereços. Se `BL func` está no endereço 1000, o LR fica com 1004 e o PC salta para `func`. Dentro de `func`, antes de chamar outra função, o LR atual (1004) vai para a pilha, porque a nova chamada vai escrever o seu próprio endereço de regresso no LR. Sem esta disciplina, o primeiro endereço de regresso perdia-se e o programa não voltava ao ponto certo.

Três erros comuns

Esquecer que o deslocamento do salto se multiplica por 4; usar um OFFSET que não é múltiplo de 8 num acesso de 64 bits; e guardar registos na pilha sem os repor pela ordem inversa. Qualquer um deles desvia o programa para um endereço errado.

## Para saber mais

*   [Simulador LEGv8](https://github.com/simdeistud/LEGv8-Simulator): simulador de código aberto para testar instruções e procedimentos antes da prova.

## Notas de rodapé

1.  Cada instrução ocupa 4 bytes seguidos, por isso os endereços de instrução andam de 4 em 4. O campo `ADDRESS` conta instruções, não bytes: o hardware multiplica por 4 para converter a contagem em endereço. [Voltar](https://resumos.rgo.pt/cadeiras/fsc/legv8-instrucoes/#user-content-fnref-unidades)
