> For the complete documentation index, see [llms.txt](https://bit-by-bit.gitbook.io/embedded-systems/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bit-by-bit.gitbook.io/embedded-systems/intel-msc-51/conjunto-de-instrucoes-e-modos-de-enderecamento.md).

# Conjunto de Instruções e Modos de Endereçamento

Nesse exemplo, a diretiva ORG \<número> determina a posição da memória em que a próxima instrução será colocada na memória de programa. Já a diretiva END indica o fim do programa.

```
    ORG 00h         ; endereço inicial do programa

    MOV A, #1       ; move valor 1 para Acumulador
LOOP:
    MOV P1, A       ; move conteúdo do Acumulador para P1
    SETB P1.4       ; faz P1.4 = 1 (pull-up interno) - pino de entrada
    JNB P1.4, CH_PR ; testa se P1.4 é igual a zero. Se sim, vai para CH_PR
    RR A            ; se não, rotaciona os bits do Acumulador para direita
    SJMP LOOP       ; pula para LOOP
CH_PR:
    RL A            ; rotaciona os bits do Acumulador para esquerda
    SJMP LOOP       ; pula para LOOP

    END
```

### Modos de Endereçamento

* **Direto:**
  * O endereço do operando é determinado pela própria instrução (endereço de 8 bits).
  * Neste caso, apenas a RAM interna e os registradores especiais podem ser acessados.
* **Indireto:**
  * O endereço do operando é determinado por um registrador.
  * Um endereço de 8 bits pode ser determinado pelos registradores R0\~R1 do banco de registradores atual, ou pelo Stack Pointer.
  * Endereços de 16 bits só podem ser especificados pelo registrador DPTR.
* **Imediato:**
  * O operando é a constante.
* **Registrador:**
  * Os registradores R0\~R7 do banco atual são acessados pela instrução.
* **Registrador Específico:**
  * A operação da instrução é realizada em um registrador específico.
  * Neste caso, não é necessário indicar um endereço.
* **Indexado:**
  * Somente a memória de programa pode ser acessada.
  * Apenas operações de leitura são possíveis.
  * Utilizado em instruções de salto e look-up table.

No último modo, os registradores PC e DPTR podem ser usados para armazenar um endereço base. Já o acumulador é utilizado para determinar o offset.

### Símbolos utilizados:

* C: Flag de carry;
* A: Acumulador;
* PC: Contador de Programa;
* DPTR: Ponteiro;
* N: Endereço de 8 bits;
* NN: Endereço de 16 bits;
* \#N: Constante de 8 bits;
* Rn: Registrador Rn (R0\~R7) do banco atual de registradores;
* @Ri: Endereço é determinado pelo registrador Ri (R0 ou R1);
* H: indica que o valor está na base hexadecimal;
* B: indica que o valor está na base binária;

### Instruções de Movimentação de Dados

![Instruções de Movimentação de Dados](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_MOV.png)

| ![Instruções de Movimentação de Dados](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_MOVX.png) | ![Instruções de Movimentação de Dados](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_MOVC.png) |
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |

De modo geral, quando o destino é o acumulador:

| MOV  | A,Rn      | Move o registro Rn para o Acumulador                                                                                             |
| ---- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| MOV  | A,N       | Move o conteúdo da memória N para o Acumulador                                                                                   |
| MOV  | A,@Ri     | Move o conteúdo da RAM endereçada por Ri para o Acumulador                                                                       |
| MOV  | A,#N      | Move a constante N para o Acumulador                                                                                             |
| MOVC | A,@A+DPTR | <p>Soma A + DPTR obtendo um endereço de 16 bits na memória de programa. Carrega o acumulador com o<br>conteúdo desta memória</p> |
| MOVC | A,@A+PC   | Idem ao anterior, mas soma A + PC                                                                                                |
| MOVX | A,@Ri     | Move o conteúdo da RAM endereçada por Ri para o Acumulador                                                                       |
| MOVX | A,@DPTR   | Move RAM externa endereçada por DPTR (endereço 16 bits) para o Acumulador                                                        |
| XCH  | A,Rn      | Troca entre si o conteúdo do Acumulador e do Registro Rn                                                                         |
| XCH  | A,N       | Troca entre si o conteúdo da memória N com Acumulador                                                                            |
| XCH  | A,@Ri     | Troca entre si a RAM endereçada por Ri com Acumulador                                                                            |
| XCHD | A,@Ri     | Troca entre si o nibble menos significativo do Acumulador e da RAM endereçada por Ri                                             |

Quando o destino é um registrador:

| MOV | Rn,A     | Move o Acumulador para o registro Rn            |
| --- | -------- | ----------------------------------------------- |
| MOV | Rn,N     | Move o conteúdo da memória N para o registro Rn |
| MOV | Rn,#N    | Move a constante N para o registro Rn           |
| MOV | DPTR,#NN | Move constante NN para o DPTR                   |

Quando o destino é um endereço direto:

| MOV  | N,A   | Move o Acumulador para a memória N                             |
| ---- | ----- | -------------------------------------------------------------- |
| MOV  | N,Rn  | Move o registro Rn para a memória N                            |
| MOV  | N1,N2 | Move o conteúdo da memória N2 para a memória N1                |
| MOV  | N,@Ri | Move RAM endereçada por Ri para a memória N                    |
| MOV  | N,#N  | Move a constante N para o conteúdo da memória N                |
| PUSH | N     | Incrementa o SP e então coloca a memória no Stack              |
| POP  | N     | Retira dado do Stack e coloca na memória, depois decrementa SP |

Quando o destino é um endereço indireto:

| MOV  | @Ri,A   | Move o Acumulador para a RAM endereçada por Ri                                      |
| ---- | ------- | ----------------------------------------------------------------------------------- |
| MOV  | @Ri,N   | <p>Move o conteúdo da memória N para a RAM endereçada<br>por Ri</p>                 |
| MOV  | @Ri,#N  | Move a constante N para a RAM endereçada por Ri                                     |
| MOVX | @DPTR,A | <p>Move Acumulador para a RAM externa endereçada por<br>DPTR (endereço 16 bits)</p> |

### Instruções Aritméticas

![Instruções aritméticas \[1\].](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_ARIT.png)

Quando o destino é o acumulador:

| ADD  | A,Rn  | Soma Rn ao Acumulador                                                    |
| ---- | ----- | ------------------------------------------------------------------------ |
| ADD  | A,N   | Soma o conteúdo da posição de memória N ao Acumulador                    |
| ADD  | A,@Ri | Soma o conteúdo da RAM endereçada por Ri ao Acumulador                   |
| ADD  | A,#N  | Soma a constante N ao Acumulador                                         |
| ADDC | A,Rn  | Soma Rn e o flag Carrry ao Acumulador                                    |
| ADDC | A,N   | Soma o conteúdo da posição de memória N e o flag Carry ao Acumulador     |
| ADDC | A,@Ri | Soma o conteúdo da RAM endereçada por Ri e o flag Carry ao Acumulador    |
| ADDC | A,#N  | Soma a constante N e flag Carry ao Acumulador                            |
| SUBB | A,Rn  | Subtrai Rn e o flag Carry do Acumulador                                  |
| SUBB | A,N   | Subtrai o conteúdo da posição de memória N e o flag Carry do Acumulador  |
| SUBB | A,@Ri | Subtrai o conteúdo da RAM endereçada por Ri e o flag Carry do Acumulador |
| SUBB | A,#N  | Subtrai a constante N e o flag Carry do Acumulador                       |
| INC  | A     | Soma 1 ao Acumulador                                                     |
| DEC  | A     | Subtrai 1 do Acumulador                                                  |
| DA   | A     | Ajuste decimal do Acumulador                                             |
| DIV  | AB    | Divide A e B, resultado: A inteiro e B resto                             |
| MUL  | AB    | Multiplica A e B, resultado: BA                                          |

Cabe ressaltar que nas operações de adição, subtração e incremento o flag de carry e de overflow são alterados. As operações de multiplicação e divisão zeram o flag de carry, e no caso da multiplicação, a flag de overflow é modificada. Além disso, a instrução de ajuste decimal também modifica a flag de carry.

Quando o destino é um registrador:

| INC | Rn | Soma 1 ao Rn    |
| --- | -- | --------------- |
| DEC | Rn | Subtrai 1 de Rn |

### Instruções Lógicas

![Instruções Lógicas \[1\].](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_LOGIC.png)

Quando o destino é o acumulador:

| ANL | A, Rn | Operação “E” entre Rn e Acumulador                                 |
| --- | ----- | ------------------------------------------------------------------ |
| ANL | A,N   | Operação “E” entre o conteúdo da memória N e o Acumulador          |
| ANL | A,@Ri | Operação “E” entre RAM endereçada por Ri e Acumulador              |
| ANL | A,#N  | Operação “E” entre a constante N e Acumulador                      |
| ORL | A,Rn  | Operação “OU” entre Rn e Acumulador                                |
| ORL | A,N   | Operação “OU” entre memória N e Acumulador                         |
| ORL | A,@Ri | Operação “OU” entre RAM endereçada por Ri e Acumulador             |
| ORL | A,#N  | Operação “OU” entre constante N e Acumulador                       |
| XRL | A,Rn  | Operação “OU EXCLUSIVO” entre Rn e Acumulador                      |
| XRL | A,N   | Operação “OU EXCLUSIVO” entre o conteúdo da memória N e Acumulador |
| XRL | A,@Ri | Operação “OU EXCLUSIVO” entre RAM endereçada por Ri e Acumulador   |
| XRL | A,#N  | Operação “OU EXCLUSIVO” entre constante N e Acumulador             |

Quando o destino é um endereço direto:

| ANL | N,A  | Operação “E” entre Acumulador e memória N                             |
| --- | ---- | --------------------------------------------------------------------- |
| ANL | N,#N | Operação “E” entre constante N e memória N                            |
| ORL | N,A  | Operação “OU” entre Acumulador e conteúdo da memória N                |
| ORL | N,#N | Operação “OU” entre constante N e conteúdo da memória N               |
| XRL | N,A  | Operação “OU EXCLUSIVO” entre Acumulador e conteúdo da memória N      |
| XRL | N,#N | Operação “OU EXCLUSIVO” entre a constante N e o conteúdo da memória N |

Operação sobre o acumulador:

| RL   | A | Faz A = 0                                                 |
| ---- | - | --------------------------------------------------------- |
| CPL  | A | Inverte o estado dos bits do Acumulador                   |
| SWAP | A | Troca os nibbles do Acumulador                            |
| RL   | A | Rotação do Acumulador para esquerda                       |
| RLC  | A | Rotação do Acumulador para esquerda através do flag Carry |
| RR   | A | Rotação do Acumulador para direita                        |
| RRC  | A | Rotação do Acumulador para direita através do flag Carry  |

### Instruções Booleanas e de Desvio

![Instruções Booleanas e de Desvio](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_BOOL.png)

Operações utilizando o endereçamento de bits:

| LR   | bit   | Zera o bit endereçado                                         |
| ---- | ----- | ------------------------------------------------------------- |
| SETB | bit   | Seta o bit endereçado                                         |
| CPL  | bit   | Inverte o estado do bit endereçado                            |
| MOV  | bit,C | Move o flag Carry para o bit endereçado                       |
| JB   | bit,N | Desvia se o bit endereçado estiver setado                     |
| JNB  | bit,N | Desvia se o bit endereçado estiver zerado                     |
| JBC  | bit,N | Desvia se o bit endereçado estiver setado e depois zera o bit |

Operações sobre o flag de Carry:

| CLR  | C      | Zera o flag Carry                                                  |
| ---- | ------ | ------------------------------------------------------------------ |
| SETB | C      | Seta o flag Carry                                                  |
| CPL  | C      | Inverte o estado do flag Carry                                     |
| MOV  | C,bit  | Move o bit endereçado para o flag Carry                            |
| ANL  | C,bit  | Operação “E” entre o bit endereçado e o flag Carry                 |
| ANL  | C,/bit | Operação “E” entre o complemento do bit endereçado e o flag Carry  |
| ORL  | C,bit  | Operação “OU” entre o bit endereçado e o flag Carry                |
| ORL  | C,/bit | Operação “OU” entre o complemento do bit endereçado e o flag Carry |
| JC   | N      | Desvia se o flag Carry estiver setado                              |
| JNC  | N      | Desvia se o flag Carry estiver zerado                              |

### Instruções de Salto

Instruções de salto incondicional são bastante simples. Basicamente, um endereço alvo é utilizado para alterar o fluxo de execução, isto é, o contador de programa. Na figura são mostradas as instruções capazes de alterar o fluxo de execução do programa, com exceção da instrução NOP, que não realiza nenhuma operação.

![Instruções de Salto \[1\].](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_JMP1.png)

As instruções JMP e CALL possuem as seguintes variações:

| ACALL | N  | Chama sub-rotina numa faixa de 2 Kbytes da atual posição            |
| ----- | -- | ------------------------------------------------------------------- |
| LCALL | NN | Chama sub-rotina em qualquer posição da memória de programa         |
| AJMP  | N  | Desvia para outro endereço numa faixa de 2 Kbytes da atual posição. |
| LJMP  | NN | Desvia para qualquer posição da memória                             |
| SJMP  | N  | Desvio curto relativo                                               |

Outras duas instruções que alteram o valor do contador de programa são as de retorno de sub-rotina e retorno de interrupção.

| RET  |   | Retorna da sub-rotina  |
| ---- | - | ---------------------- |
| RETI |   | Retorna da interrupção |

O desvio também pode ser tomado com base no resultado de uma comparação. Nesse caso, o desvio é dito condicional.

![Desvio condicional \[1\].](https://www.embarcados.com.br/wp-content/uploads/2016/10/IS_JMP2.png)

| CJNE | A,N,N    | Compara e desvia se o Acumulador for diferente do conteúdo da memória N  |
| ---- | -------- | ------------------------------------------------------------------------ |
| CJNE | A,#N,N   | Compara e desvia se o Acumulador for diferente da constante N            |
| CJNE | Rn,#N,N  | Compara e desvia se o Rn for diferente da constante N                    |
| CJNE | @Ri,#N,N | Compara e desvia se a RAM endereçada por Ri for diferente da constante N |
| DJNZ | N,N      | Decrementa o conteúdo da memória N e desvia se for diferente de “zero”   |
| DJNZ | Rn, N    | Decrementa Rn e desvia se for diferente de “zero”                        |
| JZ   | N        | Desvia se o Acumulador for “zero”                                        |
| JNZ  | N        | Desvia se o Acumulador “não for zero”                                    |

Cabe ressaltar que as instruções CJNE modificam a flag de carry.

* Exemplo de acesso a memória externa: Zera os elementos de um vetor que são iguais a FFH.

```
       ORG 00h ; endereço inicial do programa
       
       MOV DPTR, #500h ; move valor 500h para DPTR
       MOV R0, #50 ; move valor 50 para R0
LOOP: 
       MOVX A, @DPTR ; move conteúdo apontado por DPTR para Acumulador
       CJNE A, #0FFH, DIFER ; compara conteúdo do Acumulador com 0FFH. Se for diferente, vai para DIFER
       MOV A, #0 ; caso contrário, move valor 0 para Acumulador
       MOVX @DPTR, A ; move conteúdo do Acumulador para endereço apontado por DPTR
DIFER: 
       INC DPTR ; incrementa DPTR
       DJNZ R0, LOOP ; decrementa R0 e compara com 0. Se for diferente, vai para LOOP
       SJMP $ ; espera (LOOP)
 
       END
```

* Exemplo de acesso a memória externa: Copia os dados de um vetor para outro.

```
       ORG 00h ; endereço inicial do programa
       
       MOV R0, #0 ; move valor 0 para R0 (endereço de origem)
       MOV R1, #50 ; move valor 50 para R1 (número de elementos)
       MOV DPTR, #50h ; move valor 50H para DPTR (endereço de destino)
LOOP:
       MOVX A, @R0 ; move para Acumulador o conteúdo do endereço apontado por R0
       MOVX @DPTR, A ; move conteúdo do Acumulador para endereço apontado por DPTR
       INC R0 ; incrementa R0 (endereço de origem)
       INC DPTR ; incrementa DPTR (endereço de destino)
       DJNZ R1, LOOP ; decrementa R1. Se for diferente de zero, vai para LOOP
       SJMP $ ; espera
END
```

##
