Mudanças entre as edições de "MI1022806 2020 2 AULA05"
Linha 1 532: | Linha 1 532: | ||
indicada por um sufixo de duas letras no mnemonico da instrução de acordo com a tabela a seguir: | indicada por um sufixo de duas letras no mnemonico da instrução de acordo com a tabela a seguir: | ||
+ | <center> | ||
{| class="wikitable" | {| class="wikitable" | ||
|+Tabela de Sufixos de Condição de Código | |+Tabela de Sufixos de Condição de Código | ||
Linha 1 580: | Linha 1 581: | ||
|Lower or Same (sem sinal) | |Lower or Same (sem sinal) | ||
|} | |} | ||
+ | </center> | ||
<p>A maioria das instruções pode afetar ou não os indicadores de estado no CPSR. | <p>A maioria das instruções pode afetar ou não os indicadores de estado no CPSR. | ||
Linha 1 601: | Linha 1 603: | ||
As instruções de 3 argumentos são as seguintes: | As instruções de 3 argumentos são as seguintes: | ||
+ | |||
+ | <center> | ||
+ | {| class="wikitable" | ||
+ | |+Instruções de 3 argumentos | ||
+ | |- | ||
+ | |AND op1,op2,op3 | ||
+ | | op1 = op2 & op3 | ||
+ | | E bit a bit | ||
+ | |- | ||
+ | |EOR op1,op2,op3 | ||
+ | | op1 = op2 ^ op3 | ||
+ | | Ou exclusivo | ||
+ | |- | ||
+ | |ADD op1,op2,op3 | ||
+ | | op1 = op2 + op3 | ||
+ | | Soma | ||
+ | |- | ||
+ | |SUB op1,op2,op3 | ||
+ | | op1 = op2 - op3 | ||
+ | | Subtração | ||
+ | |- | ||
+ | |RSB op1,op2,op3 | ||
+ | | op1 = op3 - op2 | ||
+ | | Subtração reversa | ||
+ | |- | ||
+ | |ADC op1,op2,op3 | ||
+ | | op1 = op2 + op3 | ||
+ | | Soma com carry | ||
+ | |- | ||
+ | |SBC op1,op2,op3 | ||
+ | | op1 = op2 - op3 | ||
+ | | Subtração com carry | ||
+ | |- | ||
+ | |RSC op1,op2,op3 | ||
+ | | op1 = op3 - op2 | ||
+ | | Subtração reversa com carry | ||
+ | |- | ||
+ | |ORR op1,op2,op3 | ||
+ | | op1 = op2 | op3 | ||
+ | | Ou bit a bit | ||
+ | |- | ||
+ | |BIC op1,op2,op3 | ||
+ | | op1 = op2 & ~op3 | ||
+ | | Bit clear (zera bits) | ||
+ | |} | ||
+ | </center> | ||
<table border=1> | <table border=1> |
Edição das 15h32min de 1 de dezembro de 2020
Conjuntos de Instruções
Um programador de linguagem de alto nível normalmente conhece muito pouco acerca da arquitetura da máquina que está usando.
O conjunto de instruções da máquina é o limite em que o projetista de CPU e o programador de baixo nível enxergam, da mesma máquina.
Implementar uma CPU é uma tarefa que envolve, em grande parte, implementar um conjunto de instruções de máquina.
Já programar em linguagem de máquina (na verdade, em linguagem de montagem, Assembly) exige um conhecimento acerca do conjunto de registradores da CPU, a estrutura de memória, os tipos de dados disponíveis na máquina e o funcionamento da ULA.
Porém, da descrição do conjunto de instruções à uma compreensão sobre o funcionamento da CPU, há um longo caminho.
Características de Instruções de Máquinas
A operação de uma CPU é determinada pelas instruções que ela executa, conhecidas como instruções de máquina.
A coleção de instruções que uma determinada CPU é capaz de executar é conhecida como conjunto de instruções da CPU.
Elementos de Instrução de Máquina
Cada instrução deve conter toda a informação necessária para que a CPU possa executá-la.
A figura acima ajuda a definir os elementos da instrução:
- Código de operação (OPCODE) - Especifica a operação a ser efetuada (por exemplo, ADD, ou E/S, etc). A operação é especificada por um código binário.
Ex: Palavra de seleção (SMCn) em uma ULA de 4 bits
- Referência a operando fonte - a operação pode envolver um ou mais operandos fonte, ou seja, que constituem dados de entrada para a operação. Exemplos:
- operação com um único operando: INV(A)
- operação com dois operandos: ADD(A,B)
- operação com três ou mais operandos: DEV(GE(A,B),C,D)
- Referência a um operando de destino - a operação pode eventualmente produzir um resultado, que deverá ser enviado a um endereço de memória, ou registrador
- Endereço da próxima instrução - indica aonde a CPU deve buscar a próxima instrução (memória principal ou virtual), depois que a instrução corrente for completada, quando for o caso.
Os operandos fonte e destino podem estar localizados em:
- Memória principal ou virtual - implica em busca na memória RAM, ou no HD (quando virtual)
- Registrador da CPU - se houver apenas um registrador, a referência a ele poderá ser implícita. Quando há acumulador, a referência a ele é default. Caso hajam vários registradores, normalmente a referência a cada um, individualmente, é feita por um número inteiro correspondente.
- Dispositivo de E/S - indicado diretamente na instrução. Se for usada a E/S mapeada na memória, esta informação se resumirá a um endereço de memória, como os demais. Pode ser também um registrador específico (Ex: porta serial).
Representação de Instruções
Internamente, cada instrução é representada por uma sequência de bits.
É dividida em campos, correspondentes aos elementos da instrução.
Exemplos:
4 bits | 6 bits | 6 bits |
---|---|---|
Código da operação | Referência a operando | Referência a operando |
16 btis |
0 7 | 8 19 | 20 27 | 28 39 |
OP1 | END1 | OP2 | END2 |
---|
A maioria das CPUs têm mais de um formato de instrução.
Durante a execução, uma instrução é lida em um registrador de instruções (IR) da CPU. A CPU extrai os dados dos vários campos da instrução e efetua a operação correspondente.
Os códigos de operação normalmente são representados por abreviações, chamadas mnemônicos, que evitam que os programadores tenham que trabalhar diretamente com valores binários.
Alguns exemplos mais comuns são:
ADD ------------- Adição SUB ------------- Subtração MPY ------------- Multiplição DIV ------------- Divisão GT ------------- Operação > LT ------------- Operação < GE ------------- Operação ≥ LE ------------- Operação ≤
Os operandos também são representados por símbolos.
Por exemplo:
ADD R, Y
pode significar adicionar o valor contido na posição Y, com o valor contido no registrador R. Neste caso, Y é um endereço de memória e R, um registrador da própria CPU.
- Exercício
Em uma ULA de inteiros de 4 bits, com formato de instrução [OPCODE(5) A(4) B(4)], qual seria a instrução correspondente, se a intenção fosse executar a operação lógica Y = OR(A', B) , com A = 0001b e B = 1010?
Número de Endereços
Uma das maneiras tradicionais de se descrever uma arquitetura é em termos do número de endereços contidos em cada instrução.
Obviamente, instruções aritméticas e lógicas requerem um número maior de operandos (e de endereços, por conseguinte). Normalmente, precisam de dois operandos que serão submetidos a um cálculo ou comparação, e de um terceiro, pra armazenar o resultado.
O endereço da próxima instrução normalmente é implícito, armazenado no registrador PC.
A figura abaixo (a,b e c) compara o que seriam instruções típicas de um, dois ou três endereços, para computar a mesma linha de programação:
Y = (A - B) / (C + D x E)
Note que as instruções com 3 endereços implementaram o comando com apenas 4 instruções de máquina. Porém, instruções de 3 endereços não são muito comuns, porque implicam em instruções grandes.
No caso das instruções de 2 endereços, foram necessárias 6 linhas de código, duas a mais, portanto. Nestas instruções é típico que um dos endereços referencie tanto o operando, quanto o resultado. Gera opcodes menores, porém gera códigos maiores e exige maior habilidade do programador.
As instruções de 1 único endereço exigem que um segundo endereço seja sempre implícito (normalmente, o Acumulador - AC). Neste caso, foram necessárias 8 instruções para resolver o problema.
É possível também usar-se em expressões aritméticas uma instrução com ZERO endereço. Neste caso, é necessária uma organização de memória especial, chamada pilha. As instruções com zero endereço sempre referenciam os valores nas duas posições no topo da pilha.
Número de Endereços | Representação simbólica | Interpretação |
---|---|---|
3 | OP A, B, C | A ← B OP C |
2 | OP A, B | A ← A OP B |
1 | OP A | AC ← AC OP A |
0 | OP | T ← (T-1) OP T |
Além de tudo que foi citado, as instruções podem variar muito de tamanho porque o endereço em questão de cada operando pode se referir à memória física ou a um dos registradores da CPU. Como as memórias são muito maiores que o número de registradores, vão utilizar endereços muito mais longos.
Assim, existem máquinas que, quando vão endereçar um valor NA MEMÓRIA externa (RAM) utilizam mais de uma instrução para acessar o dado.
Tudo sempre vai depender da arquitetura da máquina.
Tipo de Instrução
Como já vimos, uma única instrução escrita em linguagem de alto nível pode requerer várias instruções de máquina.
Os tipos de instrução de máquina que existem são:
- Processamento de dados - instruções aritméticas e lógicas
- Armazenamento/transferência de dados - instruções de memória
- Movimentação de dados - instruções de E/S
- Controle - instruções de teste e de desvio
Na maioria das vezes, as instruções são autoexplicativas.
As instruções do tipo transferência de controle, no entanto, podem ser muito complexas. Em todos os casos, exceto com elas a próxima instrução a ser executada é aquele que segue imediatamente a atual, na memória.
Nas instruções de transferência de controle, a CPU atualiza o PC com o endereço de alguma outra instrução, armazenada na memória de programa.
As instruções de transferência de controle são aquelas utilizadas quando há loops no código, ou comandos de decisão ou ainda quando o código teve que ser segmentado em vários arquivos, normalmente porque estava muito extenso.
Instruções de desvio
Nestas, um dos operandos é o endereço da próxima instrução a ser executada.
Com frequência, essa instrução é do tipo desvio condicional, isto é, o desvio só ocorrerá se uma determinada condição for satisfeita. Caso contrário, o programa segue com a próxima instrução adjacente, sem alterações no PC além do incremento normal.
Estas instruções normalmente têm o nome de BRANCH ou JUMP e podem depender de uma condição, ou ser incondicionais.
Exemplo:
Instruções de chamada de procedimento
Um procedimento, ou função, ou ainda subrotina é um trecho de código independente que modulariza um programa.
O mecanismo de controle de procedimentos envolve duas instruções básicas: uma instrução de chamada, que desvia a instrução corrente para o início do procedimento, e uma instrução de retorno, que provoca o retorno da execução para o endereço onde ocorreu a chamada. Ambas são condições de desvio.
A figura abaixo ilustra o uso de procedimentos na execução de um programa.
Instruções do Pentium II e do PowerPC
Para exemplificar, apresentamos o caso especial de conjunto de instruções de um processador de propósito geral que foi muito utilizado até o início da década de (20)00.
Conjunto de Instruções do ARM
O conjunto de instruções também é chamado de "ISA - Instruction Set Architecture".
A arquitetura ARM trabalha com três tipos de instruções: o ARM, THUMB e o THUMB-2.
O conjunto THUMB de instruções de 16 bits trabalha com registradores de 32 bits.
O código THUMB é capaz de reduzir em até 65% o tamanho de um código ARM (maior densidade de código), e aumentar em até 160% o desempenho, em relação a um processador ARM equivalente, conectado a um sistema de 16 bits, apenas.
Características do ISA ARM
- 13 registradores de propósito geral:
- R0 a R7 (low registers)
- R8 a R12 (high registers)
- 3 registradores de uso/significado especial
- r13: stack pointer (SP)
- r14: link (LR)
- r15: (PC)
- 1 registrador de propósito especial
- xPSR = Program Status Register
- Registradores xPSR, PC, LR, R12, R3, R2, R1 e R0 são armazenados automaticamente na pilha quando uma interrupção ocorre.
- Arquitetura load-store: as instruções somente lidam com valores que estejam nos registradores (ou imediatos) e sempre armazenam resultados em algum registrador. O acesso à memória é feito apenas através das instruções load (para carregar o valor da memória em um registrador) e store (para armazenar o valor de um registrador na memória).
- Permite a execução condicional de várias instruções.
- Máquina de 3 endereços – dois registradores operandos e um registrador de resultado são especificados.
- 1º operando: especifica o local onde será armazenado o resultado da operação.
- Outros: valores imediatos ou locais onde se encontram os dados.
Exemplo: ADD R1, R2, #4 R1 ← (R2) + 4
- Uniformidade e tamanhos fixos dos campos das instruções para facilitar a decodificação.
- I/O mapeado em memória: a comunicação com dispositivos periféricos é feita no próprio espaço de endereçamento de memória (via load e store).
- Endereços de memória se referem a bytes individuais.
Formato de Instruções
Apesar das diferenças entre as instruções, os projetistas mantiveram certa regularidade no formato delas, facilitando a decodificação. O formato geral é do bit menos significativo ao mais significativo, o seguinte:
- 4 bits para condição de execução;
- 3 bits para o tipo de instrução;
- 5 bits para o opcode;
- 20 bits, cujo uso e repartição varia para acomodar endereços, referências a registradores,
deslocamentos e rotações.
Operandos:
Registradores:
ADD r1, r2, r3 MOV r1, r2
Imediatos: identificados pelo símbolo #
ADD r1, r2, #10 MOV r1, #0
Maiores detalhes sobre o formato das instruções podem ser vistos na figura.
Estas condições são ativadas através de sufixos que são colocados junto com os minemônicos das instruções.
Por exemplo, um salto (B) pode ser acompanhado de um NE (not equal), o que gera uma expressão BNE.
Essa instrução só será executada caso a condição seja verdadeira.
Conjunto de Instruções ARM
Quanto ao número de bits, as instruções podem ser dos seguintes tipos:
ARM
THUMB
- Operações de 32 bits, em instruções de 16 bits
- Introduzido no processador ARM7TDMI (Datasheet)
- Suportado por todos os processadores ARM, desde então
THUMB-2
- Permite uma mistura com performance otimizada de instruções de 16/32 bits
- Todas as operações do processador podem ser realizadas no estado "Thumb"
- Suportado por todos os processadores da linha Cortex-M, desde então.
Quanto ao tipo de operação, tipos de instruções oferecidos são:
- Load/Store: Instruções de carregamento e escrita de dados na memória. Podem ler/escrever
palavras inteiras(32 bits), meias-palavras(16 bits), bytes sem sinal, e podem ler e estender o sinal de meias-palavras.
A sintaxe é:
Instruções de acesso à memória
<LDR|STR> {cond} {B} {T} Rd,<Address>
onde:
- LDR carrega um valor da memória para um registrador
- STR armazena um valor de registrador para a memória
- {cond} mnemônico condicional de 2 caracteres
- {B} se B estiver presente, transfere um byte, senão, transfere uma palavra
- {T} se T estiver presente, the bit W será setado em um instrução pós-indexada, forçando um modo não-privilegiado para o ciclo de transferência. Não permitido para modo pré-indexado.
- Rd é o nome do registrador
- <Address> pode ser:
- Uma expressão que gere um endereço:
<expression>
- Uma especificação de endereço pré-fixada:
[Rn] endereço base [Rn,<#expression>]{!} offset de <expression> bytes [Rn,{+/-}Rm{,<shift>}]{!} offset de +/- conteúdos do registrador de índice, deslocado de <shift>
- Uma especificação de endereçamento pós-fixada:
[Rn],<#expression> offset de <expression> bytes [Rn],{+/-}Rm{,<shift>} offset de +/- conteúdos do registrador de índice, deslocado de <shift>
- Exemplos
STR R1,[R2,R4] ; Armazena R1 em R2+R4 (ambos os quais são ; registradores) STR R1,[R2],R4 ; Armazena R1 em R2 e escreve de volta ; R2+R4 em R2. LDR R1,[R2,#16] ; Carrega R1 do endereço R2+16, mas ; não escreve de volta. LDR R1,[R2,R3,LSL#2] ; Carrega R1 do endereço R2+R3*4. LDREQBR1,[R6,#5] ; Carrega condicionalmente o byte de R6+5 em ; R1 bits 0 a 7, preenchendo os bits 8 a 31 ; com zeros. STR R1,PLACE ; Gera um offset em PC relativo ao ; endereço PLACE.
A arquitetura ARM suporta dois tipos de instruções de load e store que transferem o conteúdo de um registrador para a memória ou ao contrário.
O primeiro tipo pode carregar ou escrever uma parava de 32 bits ou um byte sem sinal.
O segundo tipo pode ler ou escrever meia palavra de 16 bit sem sinal, e pode carregar e sinalizar meia palavra de 16 bit ou um byte. Este tipo de instrução está disponível apenas para a arquitetura ARM versão 4 ou posterior.
- Load/Store em blocos: são instruções que permitem definir a leitura/escrita de blocos de até 16 registradores em uma única instrução. Isso é feito com uma máscara de 16 bits na instrução
que define quais registradores serão usados, e permite atingir uma banda de comunicação quatro vezes maior do que uma instrução que usa um único registrador. Essas instruções podem ser usadas para início e retorno de chamadas, assim como para ler blocos de memória.
- Desvio: Todos os processadores ARM suportam instruções de branch com saltos condicionais para frente ou para trás de até 32M. A condição é dada por um campo de 4 bits. Saltos mais longos podem ser feitos através de chamadas de subrotinas como por exemplo o Branch whith Link (BL), que mantem o endereço de retorno no LR (R14).
- Processamento de Dados: são operações de adição e subtração, operações lógicas AND, OR e XOR, e instruções de comparação e teste;
- Multiplicação de inteiros: as multiplicações de inteiros podem ser feitas com operandos de 32 ou 16 bits, e o resultado pode ocupar 32 ou 64 bits;
- Adição/Subtração paralelas: essas instruções permitem aplicar a operação em partes dos operandos, de forma paralela.
Um exemplo é a instrução ADD16, que adiciona as primeiras meias-palavras dos operandos para formar a meia palavra superior do resultado, enquanto faz o mesmo com as meias-palavras inferiores para formar a parte inferior do resultado. Essas instruções são úteis para processamento de imagens
- Extensão: são instruções para reagrupar dados;
- Acesso a registrador de estado: é permitido ler e escrever em partes do registrador de estados. Existem duas instruções para mover os conteúdos de um registrador de propósito geral e de um registrador de estado, que são as seguintes:
- MRS – move o conteúdo do registrador de estado para um registrador de propósito geral.
- MSR – move o conteúdo do registrador de propósito para um registrador de estado.
- Interface para coprocessadores: há um grupo de instruções para trocas de dados com coprocessadores, assim como para controle destes. Elas permitem ao processador ARM iniciar uma operação de processamento de um coprocessador. Permite fazer transferências entre os registradores do processador e dos coprocessadores. Permitem também o processador criar endereços para o coprocessador carregar e escrever instruções. Todo o tratamento de ponto flutuante é feito por um coprocessador, cuja presença nos chips é opcional.
- Intercâmbio com Thumb: são instruções para indicar se serão executadas instruções de 32 ou 16 bits. A instrução BX permite a troca entre o estado ARM e o estado THUMB. Esta instrução copia o conteúdo de um registrador de propósito geral para o PC. Caso o bit[0] do valor transferido para o PC seja 1, o processador troca para o estado THUMB.
- instruções geradoras de exceções. Existe duas instruções deste tipo:
- a SWI que causa uma interrupção de software. É o mecanismo principal utilizado pelo ARM para poder executar códigos do Sistema Operacional no modo de usuário (User Mode).
- E existe o BKPT. Esta instrução é usada para breakpoints na arquitetura ARM da versão 5 em diante.
Programas em Instruções ARM
- Exemplo 1
- Programa calculadora simples 4 operações:
;PROGRAMA CALCULADORA DE 4 OPERAÇÕES
; R4 = 1 -> R3 = R2 + R1
; R4 = 2 -> R3 = R2 - R1
; R4 = 3 -> R3 = R2 X R1
; R4 = 4 -> R3 = R2 / R1
mov r4,#4 ; valor de R4 define operação
mov r2,#60
mov r1,#12
mov r3,#0
cmp r4,#1
blt fim
beq soma
;******
cmp r4,#2
beq subt ; se r4=2 pula para subtração
;******
cmp r4,#3
beq mult
;******
cmp r4,#4
bgt fim
beq divisao
;******
;******; ALGORITMO DE SOMA:
soma add r3,r2,r1
b fim
;******; ALGORITMO DE SUBTRAÇÃO:
subt sub r3,r2,r1
b fim
;******; ALGORITMO DE MULTIPLICAÇÃO:
mult add r3, r3, r2
sub r1, r1, #1
cmp r1, #1
bge mult
b fim
;******; ALGORITMO DE DIVISÃO:
divisao mov r4,r2
div2 subge r4,r4, r1
add r3, r3,#1
cmp r4,r1
bge div2
b fim
fim
- Exemplo 2
- Programa em instruções ARM que implementa uma calculadora de 4 operações inteiras e grava os resultados em arquivo de saída (ARMSIM):
;************************
; programa CALCULADORA
; R3 = R2 op R1
;
;onde 'op':
; R4 = 1 - SOMA
; R4 = 2 - SUBTRACAO
; R4 = 3 - MULTIPLICACAO
; R4 = 4 - DIVISAO
;*************************
OutFileHandle: .word 0
InFileHandle: .word 0
InFileName: .asciz "arqentrada.txt"
OutFileName: .asciz "ArqSaida.txt"
Saidasoma: .asciz "Soma = "
Saidasub: .asciz "Subtracao = "
Saidamult: .asciz "Multiplicacao = "
Saidadiv1: .asciz "Divisao = "
Saidadiv2: .asciz "\n Resto = "
Saidafim: .asciz "\n Fim do processamento! "
ldr r0,=InFileName
mov r1,#0
swi 0x66
swi 0x6c
;******
mov r4,r0
mov r2,#6
mov r1,#2
mov r3,#0
cmp r4,#1
blt fim
beq soma
;******
cmp r4,#2
beq subt
;******
cmp r4,#3
beq mult
;******
cmp r4,#4
bgt fim
beq divisao
;******
soma: add r3,r2,r1
ldr r0,=Saidasoma
swi 0x02
add r0,r3,#'0
swi 0x00
b fim
subt: sub r3,r2,r1
ldr r0,=Saidasub
swi 0x02
add r0,r3,#'0
swi 0x00
b fim
mult: mul r3,r2,r1
ldr r0,=Saidasoma
swi 0x02
add r0,r3,#'0
swi 0x00
b fim
divisao: mov r4,r2
div2: subge r4,r4, r1
add r3, r3,#1
cmp r4,r1
bge div2
ldr r0,=Saidadiv1
swi 0x02
add r0,r3,#'0
swi 0x00
mov r0,#'\0
swi 0x00
ldr r0,=Saidadiv2
swi 0x02
add r0,r4,#'0
swi 0x00
b fim
fim: ldr r0, =Saidafim
swi 0x02
- Exemplo 3
- Programa que executa operações aritméticas e lógicas nos operandos:
mov r1,#4
mov r2,#30
mov r3,#1
mov r4, #5
ORR R1, R2, #0x20 ;R1 = R2 | 0x20
ADD R3, R2, R4, LSL #3 ; R3 = R2 + (R4 << 3)
RSB R5, R4, #0 ; R4 = 0 - R5
SUB R1, R3, R2, LSR R4 ;R1 = R2 - (R3 >> R4)
- Exemplo 4
- Programa que executa multiplicação sem uso da instrução MUL e checando se os operandos são negativos:
; EXERCÍCIO 2 DISCIPLINA MICROPROCESSADORES
; PROFA. FERNANDA
; AULA 26/03/2019
mov r0,#8
mov r1,#-5
mov r4,#0 ; registrador de SAÍDA
inicio
cmp r1,#0
beq fim ;r1 = 0 -> r4 = 0
bgt set ;r1 >0
; r1 negativo:
rsb r3, r1, #0
rsb r2,r0, #0
b loop
set
mov r3,r1
mov r2,r0
loop
add r4,r4,r2
sub r3, r3, #1
cmp r3,#0
ble fim
b loop
fim
- Exemplo 5
- Programa que armazena um valor NA MEMÓRIA:
mov R0, #255
mov R3, #2000
mov R1, #0
str R0, [R3, R1]
- Exemplo 6
- Programa que armazena valores em espaços seguidos da memória:
mov R0, #255
mov R1, #0
mov R2, #100 //100 endereços depois do endereço-base
mov R3, #2000 //endereço base
loop
str R0, [R3,R1]
add R1, R1, #4 //endereços têm que ser múltiplos de 4
add R0, R0, #1
cmp R1, R2
blt loop
ldr R5,[R3,#20]
Ao final da execução, R3 continua contendo o valor 0X7D0 (endereço base = 2.000d)
- Exemplo 7
- Programa que armazena valores em espaços seguidos da memória e atualiza variável:
mov R0, #255
mov R1, #0
mov R2, #100 //100 endereços depois do endereço-base
mov R3, #2000 //endereço base
loop
str R0, [R3,R1]!
add R1, R1, #4 //endereços têm que ser múltiplos de 4
add R0, R0, #1
cmp R1, R2
blt loop
ldr R5,[R3,#-200]
Ao final da execução, R3 contém o valor 0X908 (endereço base = 2.312d)
- Exemplo 8
- Programa que salva dois vetores de 8 valores na memória (A, no endereço 2000 e B, no endereço 2032) e executa a operação:
c = ∑ Ai.Bi, com i variando de 0 a 7.
O produto final C será armazenado no endereço 1000 da memória
mov R0, #4 ; passo de memória
mov R10, #2000 ;endereço de A
mov R11, #2032 ;endereço de B
mov R12, #1000 ;endereço de C
;valores do vetor A
mov R2, #30
mov R3, #27
mov R4, #21
mov R5, #17
mov R6, #10
mov R7, #3
mov R8, #-1
mov R9, #-2
;grava valores de A na memória
mov R1, R10
str R2, [R1],R0
str R3, [R1],R0
str R4, [R1],R0
str R5, [R1],R0
str R6, [R1],R0
str R7, [R1],R0
str R8, [R1],R0
str R9, [R1]
;valores do vetor B
mov R2, #-3
mov R3, #1
mov R4, #7
mov R5, #11
mov R6, #13
mov R7, #23
mov R8, #4
mov R9, #5
;grava valores de B na memória
mov R1, R11
str R2, [R1],R0
str R3, [R1],R0
str R4, [R1],R0
str R5, [R1],R0
str R6, [R1],R0
str R7, [R1],R0
str R8, [R1],R0
str R9, [R1]
;rotina para multiplicação dos valores
mov R1, R10
mov R2, R11
mov R3, #0
mov R4, #7
mov R8, #0 ;registrador de saída
somatorio mov R5, #0
ldr R6, [R1],R0
ldr R7, [R2],R0
cmp R7, #0
bge multpos ;se 2o op >0 => mult positiva
beq final ;se 2o op = 0 => não acumula
;se 2o. op < 0 :
multneg sub R5, R5, R6
add R7, R7, #1
cmp R7, #0
bne multneg
b final
multpos add R5, R5, R6
sub R7, R7, #1
cmp R7, #0
bne multpos
final add R8, R8, R5
add R3, R3, #1
cmp R3, R4
ble somatorio
str R8, [R12]
Exercícios
- 1. Escreva o programa que implementa um loop com 40 iterações, incrementando uma variável do valor 0 a 39 e somando o valor 3, a cada iteração, ao valor inicial (=3) armazenado em R1.
Exemplo de solução 1 |
---|
Loop com 40 iterações e soma 3 a R1, em cada iteração ;PROGRAMA QUE IMPLEMENTA R1 = R1 + 5, 40 VEZES ; i.e., R1 = R1 x 200 ;******* mov r1, #5 ;valor inicial de R1 mov r2, #3 ;incremento de R1 mov r3, #40 ;numero de loops mov r4, #0 ;valor inicial ;***INICIA LOOP *** loop add r1, r1, r2 ;r1 = r1 + 3 add r4,r4, #1 cmp r3,r4 blt loop fim |
- 2. Escreva o programa que implementa as operações lógicas (AND, OR, XOR, NXOR, NAND E NOR) entre dois valores, armazenados em R4 e R5.
Exemplo de solução 2 |
---|
Todas as operações são bit-a-bit, e não lógicas: mov r4, #13 mov r5, #6 and r0, r4,r5 ;r0 = r4 & r5 orr r1, r4, r5 ;r1 = r4 | r5 eor r2, r4, r5 ;r2 = r4 ^ r5 mvn r3, r2 ;r3 = nxor(r4, r5) mvn r6, r0 ;r6 = nand(r4, r5) mvn r7, r1 ;r7 = nor(r4, r5) |
- 3. Implemente, no ARMSIM, o programa Arm que resolve a equação: Y = (A - B) / (C + D x E). Dica: armazene A em R0, B, em R1, C, em R2, D, em R3 e E, em R4.
Exemplo de solução 3 |
---|
Programa que resolve a equação Y = (A - B)/(C + DxE), com o resultado em R8 ;PROGRAMA QUE IMPLEMENTA Y = (A - B) / (C + D x E) ;COM: ; A = 10, B = 4, C = 2, D = 3, E = 9 ; e Y -> R8 ;****************** mov r0, #100 ;A mov r1, #4 ;B mov r2, #2 ;C mov r3, #3 ;D mov r4, #9 ;E sub r5, r0, r1 ; R5 = A - B ;*** ROTINA PARA D X E *** mov r6,r3 mov r7,r4 loop add r6, r6, r3 ; R6 = R6 + D sub r7,r7, #1 ; REPETE R7 = R4 VEZES cmp r7,#1 bgt loop add r6,r6,r2 ; R6 = (DxE) + C ;*** ROTINA PARA R8 = R5/R6 , ie, (A - B)/(C + D x E) mov r8,#0 div subge r5,r5, r6 add r8, r8,#1 cmp r5,r6 bge div fim |
- 4. Implemente, no ARMSIM, o programa que lê compara os valores armazenados em R1, R2 e R3 e devolve o maior dentre eles em R4, e o menor, em R5.
Exemplo de solução 4 |
---|
Compara R1, R2 e R3 e armazena o maior valor, dentre os 3, em R4 e o menor valor, em R5 ;PROGRAMA QUE COMPARA 3 VALORES EM R1, R2 E R3 ; E ARMAZENA O MAIOR EM R4 ; E O MENOR, EM R5 mov r1, #50 mov r2, #20 mov r3, #6 cmp r1,r2 blt r2maior cmp r1, r3 blt r3maior mov r4,r1 ; R1 eh o maior cmp r2,r3 movge r5,r3 movlt r5,r2 b fim r2maior cmp r2,r3 blt r3maior mov r4, r2 ; R2 eh o maior cmp r1,r3 movge r5,r3 movlt r5,r1 b fim r3maior mov r4, r3 ; R3 eh o maior cmp r1,r2 movge r5,r2 movlt r5,r1 b fim fim |
- 5. Escreva o programa com menu para resolver operações lógicas E, OU e NÃO entre dois valores armazenados em R4 e R5, assumindo que a variável é false quando tiver valor igual a 0 (=0).
- 6. Implemente o programa que calcula (X * 2^N), apenas pelos deslocamentos à esquerda ou direita, de um valor X armazenado em R0 e com N armazenado em R1.
Conjunto de Instruções THUMB
O THUMB possui instruções com as mesmas finalidades das instruções ARM, porém são codificadas com 16 bits.
Estas instruções THUMB geram códigos menores porém muitas vezes ocorre de aumentar o número de instruções que o processador deve executar.
Uma solução para isso são aplicações que utilizam ambos tipos de instruções (ARM e THUMB).
Aplicações deste tipo conseguem reduzir o tamanho do seu código significativamente e conseguem manter o consumo de energia baixo.
Algumas instruções THUMB são:
Instruções de deslocamento: ASR, LSL, LSR, ROR e RRX
As instruções a seguir são, na verdade, sinônimos para a instrução
MOV Rd, Rm, XXX #n
onde XXX é um dentre LSR, LSL, ASR, ROR e n é uma constante variando de 0-31.
Obs: se o sufixo S for acrecentado a XXX então o último bit deslocado de Rd entra no bit C (Carry) da palavra de estado.
Obs: os bits de uma palavra são numerados de 0 a 31, do menos significativo ao mais significativo
Sintaxe:
op{S}{cond} Rd, Rm, Rs op{S}{cond} Rd, Rm, #n RRX{S}{cond} Rd, Rm
onde:
- op is one of:
- ASR: Deslocamento à direita aritmético
- LSL: Deslocamento à esquerda lógico
- LSR: Deslocamento à direita lógico
- ROR: Rotaciona à direita
- S é um sufixo opcional. Se S for especificado, as flags condicionais são atualizadas no resultado da operação.
- Rd é o registrador destino
- Rm é o registrador contendo o valor a ser deslocado
- Rs é o registrador contendo o comprimento de deslocamento a ser aplicado ao valor em Rm. Apenas o byte menos significativo é usado e deve variar entre [0,255].
- n é o comprimento de deslocamento. Depende da instrução:
- ASR: comprimento de deslocamento de 1 a 32
- LSL: comprimento de deslocamento de 0 a 31
- LSR: comprimento de deslocamento de 1 a 32
- ROR: comprimento de deslocamento de 1 a 31
LSR Rd, #n - desloca Rd n bits para a direita inserindo n 0s à esquerda (divide Rd por 2**n)
LSL Rd, #n - desloca Rd n bits para a esquerda inserindo n 0s à direita (multiplica Rd por 2**n)
ASR Rd, #n - desloca Rd n bits para a direita, replicando o bit 31 (preserva o bit de sinal) - divide um inteiro com sinal por 2**n ROR Rd, #n - rotaciona para a direita n bits de Rd (o bit 0, - significativo, entra no lugar do bit 31)
XXX Rd, Rm,#n - variante permitida das instruções acima; Rm não muda
RRX Rd, Rm - rotaciona um bit do par (Rm,C) como se fosse uma palavra de 33 bits: Rd0->C, C->Rd31, etc
- resultado vai para Rd, Rm não é alterado, exceto se Rd=Rm.
Operação
ASR, LSL, LSR e ROR movem os bits no registrador Rm para a esquerda ou para a direita, pelo número de lugares especificado pela constante n, ou registrador Rs.
RRX move os bits no registrador Rm para a direita 1 vez.
Em todas estas instruções, o resultado é escrito para Rd, mas o valor em Rm continua inalterado.
Restrições
Não use com SP ou PC.
Flags de condição
Se S for especificado:
- estas instruções atualizam as flags N e Z de acordo com o resultado
- a flag C é atualizada com o último bit deslocado, exceto quando o comprimento do deslocamento é 0.
- Exemplos
ASR R7, R8, #9; arithmetic shift right by 9 bits LSLS R1, R2, #3; logical shift left by 3 bits with flag update LSR R4, R5, #6; logical shift right by 6 bits ROR R4, R5, R6; rotate right by the value in the bottom byte of R6 RRX R4, R5; rotate right with extend
mov r1, #-200 mov r2, #200 mov r3, #5 asr r9, r1, #3 lsls r5, r2, #4 lsl r4, r3, #6 ror r6, r1, #6 rrx r7, r3
BFC - Bit field clear e BFI - Bit field insert
Sintaxe
BFC{cond} Rd, #lsb, #width BFI{cond} Rd, Rn, #lsb, #width
onde:
- cond é o código condicional, cc.
- Rd é o registrador destino.
- Rn é o registrador fonte.
- lsb é a posição do bit menos significativo no campo de bits [0-31].
- width é a largura do campo de bits [1-32].
Operação
BFC zera um campo de bits em um registrador. Limpa width bits em Rd, iniciando da posição inferior lsb. Os demais bits permanecem inalterados.
BFI copia um campo de bits de um registrador para outro. Substitui width bits em Rd, iniciando da posição inferior lsb, pelos width bits em Rn, iniciando da posição bit[0]. Os demais bits permanecem inalterados.
Restrições
Não é permitido utilizar os registradores SP e PC com estas instruções.
Estas instruções não afetam as flags.
- Exemplos
BFC R4, #8, #12 ; Limpa o bit 8 até bit 19 (12 bits) de R4 BFI R9, R2, #8, #12 ; Substitui bits 8 a 19 (12 bits) de R9 com bits 0 a 11 de R2
AND, ORR, EOR, BIC, and ORN
E, OU, OU EXCLUSIVO, Zera bit, E NÃO-OU lógicos.
Sintaxe
op{S}{cond} {Rd,} Rn, Operand2
onde:
- op é uma das operações:
- AND: E lógico
- ORR: OU lógico ou seta-bit
- EOR: OU exclusivo lógico
- BIC: NÃO-E lógico ou zera bit
- ORN: NÃO-OU lógico
- S é o sufixo opcional. Se S for especificado, as flags de código condicional serão atualizadas como resultado da operação.
- cond é o código de condição opcional
- Rd é o registrador destino
- Rn é o registrador que contém o primeiro operando
- Operand2 é o segundo operando
Operação
As instruções AND, EOR, e ORR realizam operações E, OU-EXC e OR bit-a-bit nos valores de Rn e operand2. A instrução BIC realiza uma operação E nos bits de Rn com o complemento dos correspondentes bits no valor de operand2. A instrução ORN realiza uma operação OU nos bits de Rn com o complemento dos bits correspondentes no valor de operand2.
Restrições
Não usar em SP e PC.
Flags de condição
Se S for especificado, estas instruções:
- Atualizam as flags N e Z de acordo com o resultado.
- Podem atualizar a flag C durante o cálculo de operand2
- Não afetam a flag V
- Exemplo
AND R9, R2,#0xFF00 ORREQ R2, R0, R5 ANDS R9, R8, #0x19 EORS R7, R11, #0x18181818 BIC R0, R1, #0xab ORN R7, R11, R14, ROR #4 ORNS R7, R11, R14, ASR #32
ADD, ADC, SUB, SBC, and RSB
Soma, soma com carry, subtrai, subtrai com carry e subtrai reverso.
Sintaxe
op{S}{cond} {Rd,} Rn, Operand2 op{cond} {Rd,} Rn, #imm12; ADD and SUB only
onde:
- op é:
- ADD: Soma
- ADC: Soma com carry
- SUB: Subtração
- SBC: Subtração com carry
- RSB: Subtração reversa
- S é o sufixo opcional. Se S for especificado, as flags serão atualizadas no final da operação.
- cond é o cc
- Rd é o registrador destino. Se for omitido, o destino é o próprio Rn.
- Rn é o registrador contendo o primeiro operando
- Operand2 é o segundo operando flexível
- imm12 é qualquer valor na faixa de 0-4095
Operação
A instrução ADD adiciona o valor do operand2, ou imm12, ao valor de Rn.
A instrução ADC adiciona o valor do Rn e operand2, junto com a flag de carry.
A instrução SUB subtrai o valor de operand2 do valor em Rn. Se a flag de carry estiver zerada, o resultado é diminuído de um.
A instrução SBC subtrai o valor em Rn de operand2. Esta instrução é útil porque operand2 permite uma faixa maior de valores.
A instrução RSB subtrai o valor do operand2, ou imm12, ao valor de Rn.
A instrução ADDW é equivalente à instrução ADD, que usa o operando imm12. SUBW é equivalente à instrução SUB, que usa o operando imm12.
CBZ and CBNZ
Compara e desviam se zero; compara e desvia se não-zero.
Sintaxe:
CBZ Rn, label CBNZ Rn, label
onde:
- Rn é o registrador contendo o operando.
- label é o destino do desvio.
Operação
Use as instruções CBZ e CBNZ para evitar mudar as flags de cc e reduzir o número de instruções
A instrução CBZ Rn, label não altera as flags de condição, mas, ao contrário, é equivalente a:
CMP Rn, #0 BEQ label
A instrução CBNZ Rn, label não altera as flags de condição, mas, ao contrário, é equivalente a:
CMP Rn, #0 BNE label
Restrições
- Rn deve ser R0 a R7
- O destino do desvio deve estar entre 4 e até 130 bytes após a instrução
- Estas instruções não podem ser usadas dentro de um bloco IT.
Flags de condição
Não alteram as flags
- Exemplos
CBZ R5, target ; Forward branch if R5 is zero CBNZ R0, target ; Forward branch if R0 is not zero
CMP and CMN
Compara e compara negativo.
Sintaxe:
CMP{cond} Rn, Operand2 CMN{cond} Rn, Operand2
onde:
- cond é um código de condição opcional (c.c.)
- Rn é o registrador do primeiro operando
- Operand2 é o segundo operando
Operação
As instruções comparam o valor do registrador com operand2.
Elas atualizam a condição da flag no resultado, mas não escrevem o resultado em um registrador.
A instrução CMP subtrai o valor de operand2 do valor em Rn. Faz o mesmo que a instrução SUBS, exceto que o resultado é descartado.
A instrução CMN adiciona o valor de operand2 ao valor em Rn. Faz o mesmo que a instrução ADDS, exceto que o resultado é descartado.
Restrições
Não é permitido usar PC e operand2 não pode ser SP.
Flags de condição
As instruções atualizam as flags N, Z, C e V, de acordo com o resultado.
- Exemplos
CMP R2, R9 CMN R0, #6400 CMPGTSP, R7, LSL #2
CLZ - Count leading zeros
Sintaxe:
CLZ{cond} Rd, Rm
onde:
- cond é o cc opcional.
- Rd é o registrador destino
- Rm é registrador operando
Operação
A instrução CLZ conta o número de zeros no valor em Rm e retorna o resultado em Rd. O valor resultante é 32 se nenhum bit está setado no registrador fonte, e zero, se bit[31] é setado.
Restrições
Não use com SP e PC.
Flags de condição
Esta instrução não altera as flags.
- Exemplos
CLZ R4,R9 CLZNE R2,R3
IT - If-Then condition instruction
- Sintaxe
IT{x{y{z}}} cond
onde:
- x especifica a condição chave para a segunda instrução no bloco IT.
- y especifica a condição chave para a terceira instrução no bloco IT.
- z especifica a condição chave para a quarta instrução no bloco IT.
- cond especifica a condição chave para a primeira instrução no bloco IT.
As condições chave para segunda, terceira e quarta instruções do bloco podem ser:
- T: Then - Então. Aplica a condição cond à instrução.
- E: Else - Senão. aplica a condição inversa de cond à instrução.
Exemplo:
Operação
A instrução IT realiza um das quatro instruções condicionais seguintes.
As condições podem ser as mesmas, ou algumas podem ser o inverso lógico das outras. As instruções que seguem a instrução IT formam o "bloco IT".
As instruções no bloco IT, incluindo os branches, devem especificar a condição {cond} como parte de suas sintaxes.
Podem ser geradas exceções nos blocos IT.
Restrições
As seguintes instruções não são permitidas num bloco IT:
- IT
- CBZ e CBNZ
- CPSID e CPSIE.
Um branch ou qualquer outra instrução que modifique o PC deve estar fora de um bloco IT, ou deve ser a última instrução dentro do bloco IT. São:
- ADD PC, PC, Rm
- MOV PC, Rm
- B, BL, BX, BLX
- qualquer instrução LDM, LDR, ou POP que escreva no PC
- TBB e TBH
Não desvie para qualquer instrução INTERNA a um bloco IT, exceto quando retornando de um Exception Handler.
Para restrições adicionais, consulte o manual do seu Arm Assembler.
Flags de condição
Esta instrução não altera as flags.
- Exemplos
ITTE NE ; Proximas 3 instruções são condicionais ANDNE R0, R0, R1 ; ANDNE não atualiza as flags de condicao ADDSNE R2, R2, #1 ; ADDSNE atualiza as flags de condicao MOVEQ R2, R3 ; Move Conditional
CMP R0, #9 ; Converte valor hexa R0 (0 a 15) para ASCII ; ('0'-'9', 'A'-'F') ITE GT ; Proximas 2 instrucoes sao condicionais ADDGT R1, R0, #55 ; Converte 0xA -> 'A' ADDLE R1, R0, #48 ; Converte 0x0 -> '0'
IT GT ; bloco IT com apenas uma instrucao condicional ADDGT R1, R1, #1 ; Incrementa R1 condicionalmente
ITTEE EQ ; Proximas 4 instrucoes são condicionais MOVEQ R0, R1 ; move Condicional ADDEQ R2, R2, #10 ; add Condicional ANDNE R3, R3, #1 ; AND Condicional BNE.W dloop ; Instrucao Branch instruction apenas pode ser usada no final ; de um bloco IT
IT NE ; proxima instrucao é condicional ADD R0, R0, R1 ; erro de sintaxe: nenhum codigo condicional
Execução condicional de instruções
As instruções lógico-aritméticas podem ser condicionalmente executadas dependendo dos flags da palavra de estado que foram atualizados numa instrução anterior (usualmente imediatamente anterior).
Existem 15 condições que podem ser usadas como sufixo da instrução, e que são as mesmas usadas nas instruções de salto condicional:
eq, ne, cs ou hs, cc ou lo, mi, pl, vs, vc, hi, ls, ge, lt, gt, le, al.
Para que a execução condicional seja possível até 4 instruções devem ser precedidas pela instrução especial "If-Then condition instruction":
it cond,
onde cond é uma das 15 siglas de 2 letrasi citadas anteriormente (existem outros 3 possíveis parâmetros).
Exemplos:
(1) suponha que r1 contem um inteiro com sinal: colocar em r0 o valor absoluto desse inteiro:
movs r0, r1 @ atualiza flags it mi @ queremos tomar o negativo caso r0 <0 rsbmi r0, #0 @ faça r0 := 0 - r0 caso o bit N estivesse ligado
Obs: o mesmo código em instruções ARM seria:
mov r0, #12 mov r1, #8 mov r2, #4 loop: cmp r1, r2 @ cmp sempre atualiza flags @ queremos testar se r1 > r2 subgt r1, r1 ,r2 @ se r1 > r2, faça r1:=r1-r2 sublt r2, r2 ,r1 @ se r1 < r2 faça r2:= r2-r1 bne loop @ se r1 # r2 volte ao laço
(2) algoritmo para calcular o máximo divisor comum de dois inteiros em r1 e r2, devolvendo o resultado em r1 e r2:
loop: cmp r1, r2 @ cmp sempre atualiza flags it gt @ queremos testar se r1 > r2 subgt r1, r2 @ se r1 > r2, faça r1:=r1-r2 it lt @ senão teste por < sublt r2, r1 @ se r1 < r2 faça r2:= r2 -r1 bne loop @ se r1 # r2 volte ao laço
@ senão mdc=r1=r2
Outras instruções THUMB:
- RBIT - Reverse bits - p-81
- REV - Reverse byte order in a word - p-81 (passa uma palavre de "little endian" para "big endian" e vice-versa)
- SXTB - Sign extend a byte - p-90
- TBB - Table branch byte - p-96
- UDIV - Unsigned divide - p-86
- UMULL - Unsigned multiply (32x32), 64 bit result
- UXTB - Zero extend a byte - p-90
- CPSID/CPSIE - Interrupts Disable/Enable - p-98
Maiores informações: The Cortex-M3 instruction set
Conjunto de instruções THUMB2
Tradicionalmente todas as instruções da arquitetura ARM tem tamanho regular de 32 bits (4 bytes)
Na geração 4 de processadores ARM (Tipo ARM7-TDMI) foi incuido o conjunto de instruções alternativo THUMB em que a maioria das instruções tem 2 bytes.
Nos processadores ARM7-TDMI os conjuntos de instruções ARM e THUMB são implementados como dois modos de operação diferentes, necessitando de uma instrução especial para trocar de modo.
Na geração 7 (Cortex) foi introduzido o conjunto de instruções THUMB2 com instuções de 2 e 4 bytes que podem acessar todos os recursos do processador.
Desta forma podem-se usar instruções de 16 bits ou de 32 bits arbitrariamente sem que seja necessário trocar o modo de operação.
Nos processadores Cortex M0, M1, M2 e M3 existem apenas as instruções THUMB2. O suporte ao conjunto ARM é desabilitado.
Na família Cortex o processador de interrupções NVIC foi incorporado ao core do processador, de modo a tornar o uso de interrupções mais simples e mais eficiente que nos chips anteriores da família ARM.
Mapa de Memória
Sistemas baseados no Cortex-M3 devem ter um mapa de memória definido:
0xFFFFFFFF 0xE0000000 |
Periféricos do sistema: NVIC, debug |
0xDFFFFFFF 0xA0000000 |
Livre para Periféricos Externos |
0x9FFFFFFF 0x60000000 |
Livre para RAM Externa |
0x5FFFFFFF 0x40000000 |
Periféricos definidos pelo fabricante do CHIP |
0x3FFFFFFF 0x20000000 |
SRAM (Memória integrada no CHIP) |
0x1FFFFFFF 0x00000000 |
Memória FLASH integrada para firmware |
O arquivo de registradores
A arquitetura Cortex-M3, assim como o ARM7, tem 16 registradores (R0 a R15) de 32bits com acesso direto à ULA. Algumas instruções THUMB só podem acessar os registradores de R0 a R7.
Tres registradores tem propósito especial:
- R0 a R7
- Registradores do usuário baixos: Todas as instruções tem acesso.
- R8 a R12
- Registradores do usuário altos: Algumas instruções THUMB não tem acesso.
- R13 ou SP
- Stack Pointer. Apontador de pilha. Existem dois apontadores de pilha, ambos acessíveis como R3:
- MSP Main Stack Pointer: Este é o apontador de pilha principal, usado no núcleo do sistema operacional e no tratamento de exceções.
- PSP Process Stack Pointer: Usada em programas aplicativos (modo usuário).
As intruções PUSH e POP armazenam ou restauram dados da pilha.
PUSH {R0} ; R13 = R13-4, Memoria[R3] = R0 POP {R0} ; R0 = Memoria[R3], R13 = R13+4;
As intruções PUSH e POP podem usar uma lista de registradores:
PUSH {R0, R1, R2, R5} POP {R0-R2, R5} ; Restaura R0, R1, R2 e R5
- R14 ou LR
- Link Register. Contém o endereço de retorno para chamadas de subrotina. A instrução BL <endereço > funciona como uma chamada de subrotina. Ela salva automaticamete o endereço da intrução seuinte no LR e salta para o local indicado pelo operando. Se for necessário aninhar chamadas de subrotina, o LR deve ser salvo na pilha.
- R15 ou PC
- Program Counter. Este registrador tem o endereço da próxima instrução que será executada.
Registradores Especiais
Fora do banco de registradores R0 a R15 existem alguns registradores que controlam ou indicam aspectos especiais do processador.
Eles podem ser classificados em tres grupos:
- xPSR - APSR, IPSR, EPSR: Program Status Registers: Tem os bits de estado da ULA: NZCVQ
- PRIMASK, FAULTMASK e BASEPRI: Prioridade e mascaramento de interrupções
- CONTROL: Indica o modo de operação: Privilegiado, Usuário ou executando uma excessão
Os bits NZCV do xPSR são chamados "Condition Code" abreviado como cc.
Em geral, os códigos cc refletem o resultado da última instrução da unidade aritmética.
N Negative: É uma cópia do bit mais significativo do resultado, que indica o sinal. Resultado com bit mais significativo 1 é considerado como negativo. Setado, quando o resultado da operação for negativo, ou zerado, caso contrário
Z Zero: Indica que deu resultado ZERO na última operação. Setado, quando o resultado da operação for zero, ou zerado, caso contrário
C Carry: Bit de transporte na soma ou empréstimo na subtração. Setado, quando o resultado da operação resultar em um carry, ou zerado, caso contrário
V oVerflow: Indica overflow em uma operação com sinal. Ocorre quando mudou o sinal sem a ativação do carry. Setado, quando o resultado da operação resultar em overflow, ou zerado, caso contrário
Um carry ocorre quando:
- o resultado de uma adição for maior ou igual a 2^32
- se o resultado de uma subtração for positivo ou zero
- como resultado de um deslocamento para a direita ou esquerda.
O overflow ocorre quando o resultado de uma soma, subtração, ou comparação for maior ou igual a 2^31, ou menor que -2^31.
Muitas instruções de processamento de dados podem atualizar as flags de condição do APSR, de acordo com o resultado da operação. Algumas instruções vão atualizar todas as flags, e algumas, apenas um subconjunto. Se a flag não for atualizada, o valor original é preservado.
Você pode executar uma instrução condicionalmente, baseado em um ou mais flags atualizadas por meio de outra instrução:
- imediatamente após a instrução que atualizou as flags;
- Após um determinado intervalo de instruções que não tenham atualizado as flags.
A execução condicional está disponível pelo uso condicional de branches, ou adicionando os sufixos cc às instruções.
Sufixo | Flags | Significado |
---|---|---|
EQ | Z=1 | Equal |
NE | Z=0 | Not equal |
CS or HS | C=1 | Higher or same, unsigned >= |
CC or LO | C=0 | Lower, unsigned < |
MI | N=1 | Negative |
PL | N=0 | Positive or zero |
VS | V=1 | Overflow |
VC | V=0 | No overflow |
HI | C=1 and Z=0 | Higher, unsigned > |
LS | C=0 or Z=1 | Lower or same, unsigned <= |
GE | N=V | Greater than or equal, signed >= |
LT | N!=V | Less than, signed < |
GT | Z=0 and N=V | Greater than, signed > |
LE | Z=1 an N!=V | Less than or equal, signed <= |
Al | Can have any value | Always. This is the default when no suffix is specified. |
Os sufixos de condição de código (cc) permitem ao processador testar uma condição baseado nas flags dos registradores. Se a condição falhar, a instrução:
- Não executa
- Não escreve nenhum valor no registrador de destino
- Não afeta nenhuma flag
- Não gera nenhuma exceção
Use as instruções CBZ e CBNZ para comparar o valor de um registrador com zero e desviar, dependendo do resultado.
Todas as instruções tem um campo que permite a sua execução condicional de acordo com o estado dos bits NZCV do xPSR. Na linguagem assembly esta execução condicional é indicada por um sufixo de duas letras no mnemonico da instrução de acordo com a tabela a seguir:
CC | Condição | CC | Condição |
---|---|---|---|
CS | C=1 Carry Set | CC | C=0 Carry Clear |
EQ | Z=1 Equal (zero) | NE | Z=0 Not Equal (não zero) |
VS | V=1 Overflow Set | VC | V=0 Overflow Clear |
GT | Greater Then (com sinal) | LT | Less Then (com sinal) |
GE | Greater or Equal (com sinal) | LE | Less or Equal (com sinal) |
PL | N=0 PLus (Positivo) (com sinal) | MI | N=1 Minus (negativo) |
HI | HIgher (maior que) (sem sinal) | LO | Lower (menor que) (sem sinal) |
HS | Higher or Same (sem sinal) (mesmo que CS) | LS | Lower or Same (sem sinal) |
A maioria das instruções pode afetar ou não os indicadores de estado no CPSR. Na linguagem assembly coloca-se um sufixo com a letra s no mnemonico da instrução para indicar que os flags devem ser modificados. Por exemplo:
subs R1, R2, R3 /* Calcula R1=R2-R3 e ajusta flags */ addge R4, R4, #1 /* Soma 1 no R4 se o resultado da subs for >= 0 */ AND R5, #7 /* R5 = R5 & 7 Quado tem 2 operandos o destino=primeiro op */
As instruções de processamento de dados geralmente tem 3 argumentos:
- op1: O primeiro argumento é um registrador onde o resultado é armazenado
- op2: O segundo argumento é um registrador usado como primeiro operando da operação
- op3: O terceiro argumento é o segundo operando da operação, que pode ser um valor imediato de 8 bits, um registrador ou um registrador com deslocamento.
As instruções de 3 argumentos são as seguintes:
AND op1,op2,op3 | op1 = op2 & op3 | E bit a bit |
EOR op1,op2,op3 | op1 = op2 ^ op3 | Ou exclusivo |
ADD op1,op2,op3 | op1 = op2 + op3 | Soma |
SUB op1,op2,op3 | op1 = op2 - op3 | Subtração |
RSB op1,op2,op3 | op1 = op3 - op2 | Subtração reversa |
ADC op1,op2,op3 | op1 = op2 + op3 | Soma com carry |
SBC op1,op2,op3 | op1 = op2 - op3 | Subtração com carry |
RSC op1,op2,op3 | op1 = op3 - op2 | Subtração reversa com carry |
ORR op1,op2,op3 | op3 | Ou bit a bit |
BIC op1,op2,op3 | op1 = op2 & ~op3 | Bit clear (zera bits) |
instruções de 3 argumentos | ||
---|---|---|
AND op1,op2,op3 | op1 = op2 & op3 | E bit a bit |
EOR op1,op2,op3 | op1 = op2 ^ op3 | Ou exclusivo |
ADD op1,op2,op3 | op1 = op2 + op3 | Soma |
SUB op1,op2,op3 | op1 = op2 - op3 | Subtração |
RSB op1,op2,op3 | op1 = op3 - op2 | Subtração reversa |
ADC op1,op2,op3 | op1 = op2 + op3 | Soma com carry |
SBC op1,op2,op3 | op1 = op2 - op3 | Subtração com carry |
RSC op1,op2,op3 | op1 = op3 - op2 | Subtração reversa com carry |
ORR op1,op2,op3 | op1 = op2 | op3 | Ou bit a bit |
BIC op1,op2,op3 | op1 = op2 & ~op3 | Bit clear (zera bits) |
Nas instruções com 2 operandos o primeiro deve ser um registrador e o segundo pode ser um valor imediato de 8 bits, um registrador ou um registrador com deslocamento.
Exemplos de intruções de 3 operandos:
ORR R1, R2, #0x20 @ R1 = R2 | 0x20 ADD R2, R3, R4, LSL #3 @ R2 = R3 + (R4 << 3) RSB R4, R5, #0 @ R5 = 0 - R5 SUB R1, R2, R3, LSR R4 @ R1 = R2 - (R3 >> R4)
instruções de 2 argumentos | ||
---|---|---|
MOV op1, op2 | op1 = op2 | Copia op2 em op1 |
MVN op1, op2 | op1 = ~op2 | Copia op2 negado em op1 |
CMP op1, op2 | op1 - op2 | Compara: Subtrai ajustando CPSR sem armazenar o resultado |
CMN op1, op2 | op1 - ~op2 | Compara com o segundo operando negado |
TST op1, op2 | op1 & op2 | Testa bits: Faz E ajustando CPSR sem armazenar o resultado |
TEQ op1, op2 | op1 ^ op2 | Testa bits: Faz XOR ajustando CPSR sem armazenar o resultado |
Instruções de leitura da memória
Nesta listagem Rd e Re podem ser registradores R0 a R15.
Rd é o registrador que recebe o valor lido da memória; Re é o reg que contém o endereço de memória que será lido. offset é uma constante positiva ou negaiva de 12 bits usada para modificar o endereço.
Instruções de leitura da Memória para Registrador | ||
---|---|---|
LDR Rd,[Re, #offset] | Rd := memória[Re + offset]; | Le 32 bits |
LDRH Rd,[Re, #offset] | Rd := memória[Re + offset]; | Le 16 bits (Half word) |
LDRB Rd,[Re, #offset] | Rd := memória[Re + offset]; | Le 8 bits (Byte) |
LDR Rd,[Re, #offset]! | Rd := memória[Re + offset]; Re := Re + offset; | Le 32 bits e modifica Re |
LDR Rd,[Re, Ri] | Rd := memória[Re + Ri] | Le memória com endereço formdo pela soma de 2 registradores |
LDR Rd,[Re], #offset | Rd := memória[Re]; Re := Re + offset; | Le 32 bits e modifica Re com pós incremento |
Instruções de escrita na memória
Nesta listagem Rf e Re podem ser registradores R0 a R15.
Rf é o registrador que será armazenado na memória; Re é o reg que contém o endereço na memória. offset é uma constante positiva ou negaiva de 12 bits usada para modificar o endereço.
Instruções escrita de Registrador na Memória | ||
---|---|---|
STR Rf,[Re, #offset] | memória[Re + offset]:= Rf; | Escreve 32 bits |
STRH Rf,[Re, #offset] | memória[Re + offset]:= Rf; | Escreve 16 bits (Half word) |
STRB Rf,[Re, #offset] | memória[Re + offset]:= Rf; | Escreve 8 bits (Byte) |
STR Rf,[Re, #offset]! | memória[Re + offset]:= Rf; Re := Re + offset; | Le 32 bits e modifica Re |
STR Rd,[Re], #offset | memória[Re]:= Rf; Re := Re + offset; | Escreve 32 bits e modifica Re com pós incremento |
Instruções de salto
Salto relativo ao PC:
B enderco_destino @ Salto incondicional BEQ iguais @ Salta se Z=1 (Iguais) BCS carry_set
Chamada de subrotina:
BL subrotina1
A instrução BL salva o endereço de retorno no R14 (que é o LR Link-Rgister) e salta para a subrotina. Para reornar, da subrotina pode-se copiar o LR no PC com
subrotina1: @ Operações da subrotina MOV PC,LR @ Retorna da subrotina
O método acima não é aninhável. Não se poderia chamar outra subrotina de dentro desta subrotina
porque o valor do LR seria alterado.
Subrotinas que chamam subrotinas, devem salvar o LR na pilha:
subrotina2: PUSH {R1, R2, LR} @ Salva na pilha R1, R2, LR @ Operações da subrotina POP {R1, R2, PC} @ Restaura R1 e R2 e retorna da subrotina
Aplicativos
VISUAL (Arm)
- Disponível para download em: Visual - IDE para programação ARM
- Lista de instruções suportadas: INSTRUÇÕES ARM para Visual
- Exemplo
- Mostrar como é compilado um programa, como são acessados os registradores, os comandos mov, add, sub e str.
;--------------------------------------------------------------------
; Exercicio adaptado para ARM de Patterson pags. 54/55/56
;
; Mostra a compilacao de um comando de atribuicao em C
;
;--------------------------------------------------------------------
; Trecho em C:
;
; f = (g + h) - (i + j)
mov r1, #1 ; g=1
mov r2, #2 ; h=2
mov r3, #10 ; i=10
mov r4, #20 ; j=20
add r10, r1, r2 ; r10 = g + h
add r11, r3, r4 ; r11 = i + j
sub r0, r10, r11 ; f = r10 - r11
mov r1, #0x10000
str r0, [r1,#4]
fim
ArmSim
- Disponível para download em: ARMSim - IDE para programação ARM
Referências
- Maiores informações sobre programação em ARM:
The Definitive Guide to the ARM CORTEX-M3 2nd ed
- Processador ARM:
https://www.youtube.com/watch?v=7LqPJGnBPMM
- Curso completo de programação para sistemas embarcados:
https://www.youtube.com/playlist?list=PLPW8O6W-1chwyTzI3BHwBLbGQoPFxPAPM