terça-feira, fevereiro 06, 2007

Programação Assembly no ARM - Parte III

Continuando o nosso estudo das instruções, vamos examinar com mais detalhes o grupo de instruções de Data Processing. Este grupo contém as instruções aritméticas, lógicas e de movimentação. Estas instruções realizam uma operação sobre um ou dois operandos (Op1 e Op2) e colocam o resultado em um registrador (Rd) ou nos flags.

A figura abaixo mostra os vários campos do opcode destas instruções:

Na parte II nós já vimos os campos Cond e S. O campo Opcode determina a operação que será executada:

Opcode mne ação
0000 AND Rd := Op1 AND Op2
0001 EOR Rd := Op1 XOR Op2
0010 SUB Rd := Op1 - Op2
0011 RSB Rd := Op2 - Op1
0100 ADD Rd := Op1 + Op2
0101 ADC Rd := Op1 + Op2 + C
0110 SBC Rd := Op1 - Op2 + C - 1
0111 RSC Rd := Op2 - Op1 + C - 1
1000 TST posiciona flags conforme Op1 AND Op2
1001 TEQ posiciona flags conforme Op1 XOR Op2
1010 CMP posiciona flags conforme Op1 - Op2
1011 CMN posiciona flags conforme Op1 + Op2
1100 ORR Rd := Op1 OR Op2
1101 MOV Rd := Op2
1110 BIC Rd := Op1 AND NOT Op2
1111 MVN Rd := NOT Op2

Portanto o campo Rd determina o registrador (R0 a R15) que será o destino do resultado da operação. As instruções TST, TEQ, CMP e CMN ignoram este campo. Como o único resultado destas operações é o posicionamento dos flags, o bit S é sempre forçado pelos assemblers.

Op1 é sempre um registrador e é definido por Rn; as instruções MOV e MVN ignoram o campo Rn.

Existem duas opções para a codificação do campo Operand 2.

1. Se I for 0, o segundo operando é um registrador, cujo conteúdo pode ser deslocado:

Este deslocamento pode de quatro formas:
  • Lógico para a esquerda (LSL): desloca para a esquerda introduzindo zeros à direita
  • Lógico para a direita (LSR): desloca para a direita introduzindo zeros à esquerda
  • Aritmético para a direita (ASR): desloca para a direita repetindo o bit mais significativo na esquerda
  • Rotação para a direita (ROR): desloca para a direita, introduzindo na esquerda os bits que 'saem' à direita
Além disso, o número de bits a deslocar pode ser especificado diretamente no opcode (0 a 15) ou ser obtido de um outro registrador (neste caso é considerado o byte meno significativo do registrador, permitindo deslocamentos de 0 a 255 bits).

2. Se I for 1, o segundo operando é um valor imediato (codificado na própria instrução):
O valor de 8 bits (Imm) contido na instrução é expandido para 32 bits colocando-se zeros à esquerda e em seguida rodado para a direita o dobro de vezes do especificado em Rotate. Como Rotate tem 4 bits, isto significa que o valor pode ser rodado 0, 2, 4, 8 .. 30 bits para a direita. Embora esta codificação permita colocar um grande variedade de constantes na instrução, uma quantidade ainda maior não tem como ser codificada. Neste caso o valor precisa ser armazenado em uma posição da memória e carregado para um registrador antes de executar a operação. Por exemplo, as constantes 0, 1, 0x100 e 0x110 podem ser codificadas mas 0x101 não.

Vejamos agora como escrever estas instruções na linguagem Assembly.

MOV e MVN
{cond}{S} Rd,

CMP,CMN,TEQ,TST
{cond} Rn,

AND,EOR,SUB,RSB,ADD,ADC,SBC,RSC,ORR,BIC
{cond}{S} Rd,Rn,

onde

é o mnemônico da instrução
{cond} é a condição (opcional)
{S} indica que pode ser acrescentado S para a instrução afetar os flags
pode ser Rm{,} ou <#expressão>
pode ser Rs ou #expressão
é ASL, LSL, LSR, ASR ou ROR
Rd, Rn, Rm e Rs são os registradores R0 a R15

Quando Op2 for especificado com #expressão, o assembler tentará codificá-lo em um valor imediato. Se não conseguir, acusará erro.

Vejamos se alguns exemplos esclarecem um pouco:

MOV R1,#100 ; coloca 100 em R1
MOVS R1,R0 ; coloca o conteúdo de R0 em R1, atualiza os flags
MOV R1,R0 ASL 5 ; coloca R0 * 32 em R1
MOV R1, R0 ROR R2 ; coloca em R1 o valor de R0 rodado para a direita de R2 bits
ADD R2,R1,R0 ; soma R1 a R0 e coloca o resultado em R2
ADD R1,R1,#1 ; incrementa R1
CMP R1,R2 ; compara R1 a R2, flags posicionados cf R1-R2
TST R1,#0x80000000 ; testa o bit mais significativo de R1
BIC R1,R1,#1 ; zera o bit menos significativo de R1

No próximo post da série vamos ver como acessar dados na memória. Até lá!

Nenhum comentário: