Manual Assembly - Principal

Transcrição

Manual Assembly - Principal
FACAP E
FACULDADE DE CIÊNCIAS APLICADAS E SOCIAIS DE PETROLINA
CIÊNCIA DA COMPUTAÇÃO
Assembly
MANUAL DE REFERÊNCIA
Prof. Jorge Cavalcanti
[email protected]
Prof. Sérgio Faustino
[email protected]
Laboratório de Arquitetura de Computadores
1. INTRODUÇÃO
Este manual objetiva abordar superficialmente diversos tópicos relacionados ao conjunto de instruções dos
microprocessadores 8086/88. É o suporte necessário aos diversos experimentos que são realizados utilizando o
SID como depurador assembly. Inicialmente é apresentada uma rápida revisão sobre sistemas de numeração e
suas conversões, depois são feitos comentários sobre os microprocessadores apresentando a arquitetura do
8086/88. A partir de então são descritos os diversos registradores e flags utilizados pelo microprocessador, e
finalmente são apresentadas as principais instruções assembly utilizadas nos experimentos com suas funções. No
final são mostrados pequenos programas exemplos fazendo uso de interrupções. Qualquer conhecimento mais
aprofundado consulte livros específicos indicados na bibliografia.
2. CONVERSÃO ENTRE SISTEMAS DE NUMERAÇÃO
Existem vários sistemas numéricos, dentre os quais se destacam: o sistema decimal, o binário, o octal e o
hexadecimal. Os sistemas binário e hexadecimal são muito importantes nas áreas de técnicas digitais e
informática pois há uma forte ligação entre estes sistemas de numeração e os circuitos lógicos.
Utilizando o conceito básico de formação de um número, obtém-se o equivalente decimal do número
binário 10012 da seguinte forma:
23
1
22
0
21
0
20
1
1 x 23 + 0 x 22 + 0 x 21 + 1 x 20 =
1 x 8 + 1 x 1 = 910 ∴ 10012 = 910
Será visto agora a transformação inversa, ou seja, a conversão de um número do sistema decimal para o
sistema binário. Para converter 4710 em binário faz-se:
47 ÷ 2 = 23
23 ÷ 2 = 11
11 ÷ 2 = 5
5÷2=2
2÷2=1
1÷2=0
1° resto = 1
2° resto = 1
3° resto = 1
4° resto = 1
5° resto = 0
6° resto = 1
O último resto será o algarismo mais significativo e ficará à esquerda. Os outros algarismos seguem-se
na ordem até o primeiro resto. Logo:
4710 = 1011112
O sistema hexadecimal possui 16 algarismos, sendo sua base igual a 16. Os algarismos são assim
enumerados:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, e F
A tabela 1 mostra a seqüência de numeração do sistema hexadecimal ate a quantidade dezoito.
A regra de conversão do sistema hexadecimal para o sistema decimal é análoga à de outros sistemas,
somente neste caso, a base é 16. Como exemplo, será convertido o número 3F16 em decimal.
161
3
160
F
3 x 161 + F x 160 =
sendo F16 = 1510, substituindo:
3 x 161 + 15 x 160 = 3 x 16 + 15 x 1 = 6310 ∴ 3F16 = 6310
2
Tabela 1 – Seqüência de numeração hexadecimal e binária.
DECIMAL
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HEXADECIMAL
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
10
11
12
BINÁRIO
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
10000
10001
10010
A conversão do sistema decimal para hexadecimal se dá da seguinte forma, considerando a conversão do
número 100010 em hexa:
1000 ÷ 16 = 62
62 ÷ 16 = 3
3 ÷ 16 = 0
1° resto = 8
2° resto = 14
3° resto = 3
sendo 1410 = E16 , temos:
100010 = 3E816
Para converter números hexadecimais em binários necessitam-se de 4 bits para representar cada
algarismo hexadecimal. Por exemplo, para converter o número C1316 para o sistema binário, faz-se:
C
1100
1
0001
3
0011
∴ C1316 = 1100000100112
A conversão do sistema binário para o sistema hexadecimal é feita agrupando-se os dígitos binários de 4
em 4 bits da direita para a esquerda. Por exemplo, para transformar o número 100110002 em hexadecimal:
1001 1000 ∴ 100110002 = 9816
9
8
3. OPERAÇÕES ARITMÉTICAS NO SISTEMA BINÁRIO
Para efetuar a adição no sistema binário, deve-se agir como numa adição convencional no sistema decimal,
lembrando que, no sistema binário, tem-se apenas 2 algarismos.
Para exemplificar, serão somados os números binários 1102 e 1112.
3
∴ 1102 + 1112 = 11012
verificação: (610 + 710 = 1310)
O método de subtração no sistema binário é análogo a uma subtração no sistema decimal.
Observa-se que para o caso 0 – 1, o resultado será igual a 1, porém haverá um transporte para a coluna
seguinte que deve ser acumulado no subtraendo e, obviamente, subtraído do minuendo. Por exemplo, é mostrada
abaixo a resolução da operação 10002 – 1112 passo a passo.
4. MICROPROCESSADORES
Este componente é o principal responsável pelo desempenho de um microcomputador. Exemplos de
microprocessadores usados nos PCs são o Pentium, o 486 e o 386, além de outros, é claro. Todos os
microprocessadores usados nos PCs são descendentes do 8086, o primeiro microprocessador de 16 bits lançado
pela Intel, no final dos anos 70. Antes deles, reinavam os microprocessadores de 8 bits, entre os quais pode-se
citar o 8080, 0 8085, o Z80, o 6502, o 6800 e o 6809.
Um microprocessador é um chip que contém o que é chamado de Unidade Central de Processamento
(em inglês, Central Processing Unit, ou CPU). É responsável por buscar e executar instruções existentes na
memória. Essas instruções são chamadas de linguagem assembly ou propriamente “linguagem de máquina”. São
comandos muito simples, como operações aritméticas e lógicas, leituras, gravações, comparações e
movimentações de dados. Essas instruções simples, quando agrupadas, formam os programas.
4.1 8086
Lançado pela Intel em 1978, o 8086 tinha um desempenho dez vezes melhor que seu antecessor o 8080. Seus
registradores tinham a largura de 16 bits, o barramento de dados passou de 8 para 16 bits e o barramento de
4
endereços se tornou maior com 20 bits de largura, permitindo assim que fosse controlado mais de 1 milhão de
bytes de memória. A memória passou a ser tratada de maneira diferente pois esse processador tratava a mesma
como se fosse dividida em até 16 segmentos contendo 64 kilobytes cada, e não permitia que nenhuma estrutura
de dados ultrapassasse a barreira entre os segmentos.
4.2 8088
O 8088 surgiu da necessidade em se criar um processador com características parecidas com as do 8086 mas que
tivesse um custo menor. Dessa forma, a Intel colocou no mercado um chip que só se diferenciava do 8086 pelo
fato de ter um barramento de dados de 8 bits. Em virtude de sua concepção menos avançada e do baixo custo de
produção o 8088 foi escolhido pela IBM, para o projeto de seu computador pessoal, pois, além de possuir o
projeto interno de 16 bits também pertencia à mesma linhagem do 8080.
A figura 1 apresenta o diagrama de blocos do microprocessador 8086/88.
Figura 1 – Diagrama de Blocos do 8086/88.
5. O QUE É ASSEMBLY ?
Assembly é uma linguagem de baixo nível, que pode ser usado em conjunto com linguagens de alto nível para
acelerar tarefas lentas. Basicamente ela consiste de sentenças que representam instruções em linguagem de
máquina, e, como está próxima ao código de máquina, ela é rápida.
Há décadas atrás, quando surgiu o 8086, programar não era uma tarefa fácil. Quando os primeiros
computadores foram desenvolvidos, a programação tinha que ser feita em código de máquina. Como não era
uma tarefa fácil criaram a linguagem Assembly. Para programar em assembly é necessário o tradutor assembler,
um programa de computador que produz um código binário correspondente a cada mnemônico (instrução
assembly). Os programas de tradução avisam quando encontra algum erro no programa fonte. Nos experimentos
em laboratório será utilizado o SID como tradutor assembler.
5.1 Por que aprender assembly ?
A primeira razão para se trabalhar com assembly é a oportunidade de conhecer melhor o funcionamento do PC,
o que permite o desenvolvimento de programas de forma mais consistente. Uma outra razão é que programas
assembly são mais rápidos, menores e mais poderosos do que os criados com outras linguagens. Também
5
oferece maior flexibilidade e controle sobre o PC, ao nível de hardware. Além do mais, o assembler (montador)
permite uma otimização ideal nos programas, seja no seu tamanho ou execução. Uma outra vantagem é que o
programador assembly tem acesso a todos os recursos e instruções disponíveis na máquina. O programador de
linguagem de alto nível não tem este acesso. Por exemplo, se for necessário verificar um bit de estouro
(overflow) em um registrador, um programa assembly pode testá-lo, mas não um programa Pascal.
6. REGISTRADORES E FLAGS NO 8086/88
Quando se está trabalhando com assembly, tem-se que usar registradores. Pode-se imaginá-los como sendo
variáveis já definidas para o programador. O 8086/88 possui 14 registradores distribuídos nas unidades internas
EU (Unidade de Execução) e BIU (Unidade de Interface com o Barramento). Segundo a Intel, os registradores
podem ser agrupados da seguinte forma:
Registradores de Uso Geral: AX, BX, CX, DX, SP, SI e DI;
Registradores de Segmento: CS, DS, SS e ES;
Apontador de Instrução: IP;
Registrador de FLAGS.
6.1 Registradores de Uso Geral (AX, BX, CX, DX, SP, SI e DI)
Estes registradores são definidos como registradores de uso geral pois se pode realmente armazenar qualquer
coisa neles. São também registradores de 16 bits, o que significa que é possível armazenar um inteiro positivo de
0 a 65535, ou um inteiro com sinal de -32768 to 32768. Então se tiver que armazenar 0A4C (hexadecimal) em
AX, AH conterá 0A, e AL conterá 4C. Os registradores de uso geral são subdivididos em dois conjuntos de 4
registradores:
Registradores de Dados: AX, BX, CX e DX. Seus bytes superiores (AH, BH, CH e DH) e inferiores
(AL, BL, CL e DL) podem ser acessados de modo separado. Isto significa que cada registrador pode
ser usado como um registrador de 8 ou 16 bits. Isto é vantajoso porque evita o uso de registradores de
16 bits quando se realizam operações de 8 bits. Eles podem ser utilizados sem restrições na maioria
das operações lógicas e aritméticas. Como será visto a seguir, adicionalmente algumas instruções
usam certos registradores de forma implícita, permitindo uma poderosa forma de codificação.
Registradores Apontadores e de Indexação: SP, BP, SI e DI. Todo acesso é feito em 16 bits.
Podem também participar da maioria das operações lógicas e aritméticas.
Registrador AX (AH + AL)
Também denominado acumulador primário. Todas as operações de I/O são realizadas através deste registrador.
As operações que utilizam dados imediatos necessitam de menos memória quando são feitas através de AX.
Geralmente é utilizado como hospedeiro para valores retornados de sub-rotinas.
Registrador BX (BH + BL)
Também denominado Registrador Base. Usado preferencialmente como apontador da base de uma tabela de
dados. Todas as referências à memória que usam esse registrador no cálculo do endereço usam o registrador DS
como segmento padrão.
Registrador CX (CH + CL)
Também denominado contador, sendo usado prioritariamente para contar o número de interações no interior de
um loop e também na manipulação de strings. Ele é decrementado durante as operações envolvendo loops e
strings. Também utilizado na rotação e deslocamento de vários bits.
6
Registrador DX (DH + DL)
Também chamado de registrador de dados ou endereçador de I/O. É usado para guardar dados de 16 bits nas
operações com a ULA e controle indireto de I/O. Pode ser usado por compiladores para retornar valores de subrotinas.
Registrador SP
É denominado Stack Pointer (Ponteiro de Pilha). Utilizado juntamente com BP para acessar dados no segmento
da pilha. Armazena o “offset” do endereço do topo da pilha. Todas as referências ao SP, por definição, utilizam
juntamente o registrador de segmento SS. Também pode ser usado como operando em operações lógicas e
aritméticas de 16 bits.
Registrador BP
É denominado Base Pointer (Ponteiro da Base). Permite acessar dados no segmento da pilha. Tipicamente é
usado para acessar parâmetros que foram passados pela pilha. Também pode ser usado como operando em
operações lógicas e aritméticas de 16 bits.
Registradores de Indexação (SI e DI)
São denominados Source Index (Índice de Origem) e Destination Index (Índice de Destino). São usados para
acessar dados na memória de dados. São extensivamente usados nas operações com strings. Também podem ser
usados como operando em operações lógicas e aritméticas de 16 bits.
6.2 Registradores de Segmentos
A memória do 8086/88 é dividida em segmentos lógicos de até 64 Kb. A CPU tem acesso simultâneo a até 4
segmentos, utilizando os seguintes registradores como seletores de endereço: CS, DS, SS e ES. Estes
registradores estão localizados na BIU, sendo acessíveis para programas, podendo ser manipulados por várias
instruções. São descritas a seguir as principais funções de cada um destes registradores.
Registrador CS
É denominado Code Segment (Segmento de Código). É utilizado para montar o endereço de uma instrução
(code) a ser buscada (fetch) na memória. CS define o endereço base (segmento) e deve ser somado ao registrador
IP (também localizado na BIU) para formar o endereço de 20 bits da instrução. Em outras palavras, aponta para
o segmento de código de instrução em uso.
Registrador DS
É denominado Data Segment (Segmento de Dados). Aponta para os segmentos de dados onde geralmente são
armazenadas as variáveis de programa. Em conjunto com IP define o endereço efetivo do dado a ser lido ou
escrito na memória.
Registrador SS
É denominado Stack Segment (Segmento de Pilha). Aponta para o segmento da pilha em uso. Todos os acessos à
pilha utilizam os registradores SP e BP e utilizam como referência o registrador de segmento de pilha (SS).
Registrador ES
É denominado Extra Segment (Segmento Extra). É uma opção extra para apontar a base de um segmento de
dados (strings). Por exemplo, ele é utilizado juntamente com o DI para formar o endereço da base de strings de
dados.
7
6.3 Registrador IP
É denominado Instruction Pointer (Ponteiro de Instruções). Este registrador é atualizado pela BIU e contém a
distância em bytes (offset) da próxima instrução em relação ao início do código que está sendo executado, isto é,
ele aponta para a próxima instrução. Os programadores não têm acesso direto ao registrador.
6.4 Registrador de FLAGs
O microprocessador 8086/88 contém em seu interior um total de 9 sinalizadores, também conhecidos como
flags. Eles existem para indicar resultados obtidos sempre na última operação lógica ou aritmética executada, ou
para definir o comportamento do microprocessador na execução de certas instruções. Estes 9 flags estão
agrupados, para facilidade de acesso, em um registrador de 16 bits, chamado de Registrador de Flags,
Registrador de Estado ou Palavra de Estado do Programa, sendo localizado na EU. Como mostra a figura 2, ele
utiliza bits para armazenar informações de estado (status) e de controle.
15
14
13
12
11
O
10
D
9
I
8
T
7
S
6
Z
5
4
A
3
2
P
1
0
C
Figura 2 – Registrador de Flags do 8086/88.
−
−
Flags de estado: O, S, Z, P, C e A.
Flags de controle: T, D, I.
6.4.1 Flags de Estado
Os bits de estado refletem certas propriedades de resultados de operações lógicas e aritméticas realizadas na EU,
a qual é responsável por “setar” estes bits no registrador. A seguir é descrito o significado dos flags de estado.
−
Flag A (Auxiliary): reflete o “vai um” do terceiro bit de uma operação de 8 bits. É utilizado por instruções
que trabalham com operações decimais.
−
Flag C (Carry): reflete o “vai um” do bit mais significativo nas operações aritméticas (de 8 e 16 bits). É
também modificado por algumas instruções de rotação e deslocamento.
−
Flag O (Overflow): é setado quando o resultado de uma operação aritmética excede os limites da área
destinada ao armazenamento (que pode ser 8 ou 16 bits). Ou quando ocorre um “vai um” do penúltimo bit
mais significativo para o último bit mais significativo. Se o registrador ou variável for de 8 bits, e O = 1,
significa que houve um “vai um” do 6º para o 7º bit do registrador ou variável. Se o registrador ou variável
for de 16 bits, e O = 1, significa que houve um “vai um” do 14º para 15º bit do registrador ou variável.
−
Flag S (Sign): é igual ao bit de mais alta ordem do resultado de uma operação aritmética, ou seja, indica se
o resultado da operação é positivo (S = 0) ou negativo (S = 1).
−
Flag P (Parity): indica a paridade (par) dos 8 bits menos significativos do resultado da operação realizada
(aritmética ou lógica):
P = 1 → número par de “1” nos 8 bits menos significativos.
P = 0 → número ímpar de “1” nos 8 bits menos significativos.
−
Flag Z (Zero): é setado (Z = 1) se o resultado da operação for igual a zero.
6.4.2 Flags de Controle
Existem 3 flags que podem ser setados pelos programas, alterando as operações do processador:
−
Flag D (Direction): determina se as operações de string devem ser auto-decrementadas (D = l) ou
incrementadas (D = 0). Em outras palavras, determina se as operações com strings vão incrementar ou
decrementar os registradores de indexação (SI e DI).
8
−
Flag I (Interrupt Enable): caso a CPU esteja habilitada para receber instruções mascaráveis, então I = l.
Caso contrário, I = 0 desabilita interrupções mascaráveis.
−
Flag T (Trap): utilizado para depuração de programa. Se T = 1, o processador executará as instruções
passo a passo.
7. INSTRUÇÕES DO MICROPROCESSADOR
Para que um programa possa ser executado por um computador, ele precisa ser constituído de uma série de
instruções de máquina e estar armazenado em células sucessivas na memória principal. A CPU é responsável
pela execução das instruções que estão na memória.
Quem executa um programa é o hardware e o que ele espera encontrar é um programa em linguagem de
máquina (uma seqüência de instruções de máquina em código binário). A linguagem de máquina é composta de
códigos binários, representando instruções, endereços e dados e está totalmente vinculada ao conjunto de
instruções do microprocessador.
Um ser humano usa seu conhecimento e inteligência para traduzir uma tarefa complexa (tal como, por
exemplo, a tarefa de buscar uma pasta em um arquivo) em uma série de passos elementares (identificar o móvel
e gaveta onde está a pasta, andar até o móvel, abrir a gaveta. encontrar a pasta, retirar a pasta e fechar a gaveta).
Para o computador, uma instrução precisa ser detalhada, dividida em pequenas etapas de operações, que são
dependentes do conjunto de instruções do microprocessador e individualmente executáveis.
7.1 Conjunto de Instruções
A tabela 2 apresenta um conjunto das principais instruções utilizadas nos experimentos de laboratório. Para
maiores detalhes consulte livros específicos indicados na bibliografia.
Tabela 2 – Conjunto de Instruções do 8086/88.
INSTRUÇÃO
OPERAÇÃO
AAA
Ascii Adjust for Addition (Ajuste Ascii para Adição): Altera o conteúdo de
AL para um decimal válido.
AAS
Ascii Adjust for Subtraction (Ajuste Ascii para Subtração): Corrige o
resultado de uma subtração de decimais em AL.
ADC destino, Add with Carry (Adição com Carry): Soma dois operandos binários e põe o
fonte
resultado no destino. Se C estiver setado, soma 1 ao resultado.
ADD destino, Arithmetic Addition (Soma Aritmética): Soma fonte e destino, repondo o
fonte
valor original do destino. Ambos os operandos são binários.
AND destino, Logical And (E Lógico): Faz um E Lógico entre os dois operandos,
fonte
substituindo o destino com o resultado.
Procedure Call (Procedimento de Chamada): Põe o Ponteiro de Instrução (e o
CALL destino Segmento de Código para chamadas do tipo far) na pilha e carrega o Ponteiro
de Instrução com o endereço do nome do procedimento. O código continua
com a execução em CS:IP.
CLC
Clear Carry (Limpa Carry): Limpa (zera) o Flag Carry.
Clear Direction Flag (Limpa o Flag de Direção): Limpa (zera) o Flag de
CLD
Direção levando instruções de string a incrementar os índices dos
registradores SI e DI.
CMP destino, Compare (Compara): Subtrai a fonte do destino, atualiza os flags mas não
fonte
guarda o resultado (não altera os valores de destino e fonte).
Decimal Adjust for Addition (Ajuste Decimal para Adição): Corrige o
DAA
resultado (em AL) de uma operação BCD de adição prévia. O conteúdo de
AL é modificado para um par de dígitos decimais.
FLAGS
Aft: A, CXXX
Ind: P, S, Z, O
Aft: A, C
Ind: P, S, Z, O
Aft: A, C, O, P,
S, Z
Aft: A, C, O, P,
S, Z
Aft: C,O,P,S,Z
Ind: A
AAAXXXXX
–
Aft: C
Aft: D
Aft: A, C, O, P
S, Z
Aft: A,C,P,S,Z
Ind: O
9
Decimal Adjust for Subtraction (Ajuste Decimal para Subtração): Corrige o
resultado (em AL) de uma operação BCD de subtração prévia. O conteúdo de
AL é modificado para um par de dígitos decimais.
DEC destino
Decrement (Decrementa): Subtração binária sem sinal de um (1) do destino.
Divide: Divisão sem sinal do acumulador pela fonte. Se o divisor fonte for
DIV fonte
um valor byte, então BL é dividido pela fonte e o quociente é colocado em
BL e o resto em BH. Se o operando fonte for um valor word, então DX:AX é
dividido pela fonte e o quociente é colocado em BX e o resto em DX.
INC destino
Increment (Incremento): adiciona um (1) ao operando binário sem sinal
destino.
Interrupt (Interrupção): inicia uma interrupção por software colocando (push)
os flags na pilha, limpando a Trap e os flags de Interrupção, pondo (push) CS
INT valor
seguido do IP na pilha e carregando CS:IP com os valores encontrados na
tabela de vetores de interrupção. A execução começa no ponto endereçado
pelo novo CS:IP.
Jxx
TODOS OS SALTOS (JUMPS) CONDICIONAIS (ver tabela 3)
Jump if Register CX is Zero (Salte se o Registrador CX for Zero): desvia a
JCXZ label
execução para “label” se CX for zero. Usa uma comparação sem sinal.
Obs: “label” é o endereço da instrução a ser executada.
Uncoditional Jump (Salto Incondicional): transfere o controle para “label”
JMP label
incondicionalmente. Os saltos estão entre -32768 e 32767 bytes distantes da
instrução seguinte ao salto. Saltos NEAR e SHORT provocam a atualização
do IP, enquanto que saltos FAR provocam a atualização de CS e IP.
Decrement CX and Loop if CX Not Zero (Decrementa CX e faz Loop se CX
LOOP label
for Não Zero): decrementa CX em 1 e transfere o controle para “label” se CX
não for zero. O operando “label” precisa estar a -128 ou 127 bytes da
instrução que segue a instrução de loop.
Loop While Equal / Loop While Zero (Loop enquanto Igual / Loop enquanto
LOOPE label Zero): decrementa CX em 1 (sem modificar flags) e transfere o controle para
LOOPZ label “label” se CX não for zero e o flag Zero estiver setado. O operando “label”
precisa estar a -128 ou 127 bytes da instrução que segue a instrução de loop.
Loop While Not Zero / Loop While Not Equal (Loop enquanto Não Zero /
LOOPNZ label Loop enquanto Não Igual): decrementa CX em 1 (sem modificar flags) e
LOOPNE label transfere o controle para “label” se CX não for zero e o flag Zero estiver
resetado (zerado). O operando “label” precisa estar a -128 ou 127 bytes da
instrução que segue a instrução de loop.
Move Byte or Word (Move Byte ou Word): copia um byte ou word do
MOV destino, operando fonte para o operando destino. Se o destino é SS, as interrupções
fonte
são desabilitadas, exceto nas CPUs 808x mais antigas e com bug. Algumas
CPUs desabilitam as interrupções se o destino for um dos registradores de
segmento. Não copia byte ou word de memória para memória.
MOVS destino, Move String - Byte or Word (Move String - Byte ou Word): copia dados
fonte
endereçados por DS:SI (mesmo que um operando seja fornecido) para a
localização ES:DI e atualiza SI e DI baseado no tamanho do operando ou da
MOVSB
MOVSW
instrução usada. Se o flag de direção estiver resetado (zerado), SI e DI são
MOVSD
incrementados, se estiver setado, SI e DI são decrementados. Use com REP.
Unsigned Multiply (Multiplicação sem Sinal): multiplicação sem sinal do
MUL fonte
acumulador pela fonte. Se a fonte for um valor byte, então AL é usado como
o outro multiplicando e o resultado é colocado em AX. Se a fonte for um
valor word, então AX é multiplicado pela fonte e EX:AX recebe o resultado.
NEG destino
Two's Complement Negation (Negação com Complemento de 2): subtrai o
destino de 0 (zero) e salva o complemento de 2 no próprio destino.
DAS
Aft: A,C,P,S,Z
Aft: A,O,P,S,Z
Ind: A, C, O,
P, S, Z
Aft: A, O, P,
S, Z
Aft: I, T
–
–
–
–
–
–
–
–
Aft: C, O
Ind: A, P, S, Z
Aft: A, C, O,
P, S, Z
10
No Operation (Nenhuma Operação): esta é uma instrução de fazer nada.
Resulta na ocupação tanto de espaço quanto de tempo e é muito útil para
fazer patches em segmentos de código.
One's Complement Negation - Logical NOT (Negação com Complemento de
NOT destino
1 - NÃO Lógico): Inverte os bits do operando destino formando seu
complemento de 1.
OR destino,
Inclusive Logical OR (OU Inclusive Lógico): OU Inclusive Lógico dos dois
fonte
operandos, retornando o resultado no destino. Todos os bits ativos em
qualquer dos operandos estará ativo no resultado.
POP destino
Pop Word off Stack (Tire Word da Pilha): transfere o word do topo da pilha
(SS:SP) para destino e incrementa SP em 2 para indicar o novo topo de pilha.
POPF
Pop Flags off Stack (Tire os Flags da Pilha): tira word da pilha e os transfere
para os registradores de flags. Depois incrementa SP em 2.
Push Word onto Stack (Ponha Word na Pilha): decrementa SP pelo tamanho
PUSH fonte
do operando (dois, ou quatro, valores byte são estendidos por sinal) e
transfere um word da fonte para o topo da pilha (SS:SP)
PUSHF
Push Flags onto Stack (Ponha os Flags na Pilha): transfere os registradores de
flags para a pilha. PUSHF guarda um valor de 16 bits.
Rotate Through Carry Left (Rolar através do Carry para a Esquerda): Rola os
RCL destino, bits do destino para a esquerda as “vezes” indicadas com todos os dados que
vezes
“vazarem” pela esquerda re-entrando pela direita. O flag de carry conterá o
valor do último bit rolado.
Rotate Through Carry Right (Rolar através do Carry para a Direita): Rola os
RCR destino, bits do destino para a direita as “vezes” indicadas com todos os dados que
vezes
“vazarem” pela direita re-entrando pela esquerda. O flag de carry conterá o
valor do último bit rolado.
ROL destino, Rotate Left (Rotação para a Esquerda): Rola os bits do destino para a
vezes
esquerda as “vezes” indicadas com todos os dados que “vazarem” pela
esquerda re-entrando pela direita. O flag C conterá o último bit rolado.
ROR destino, Rotate Right (Rotação para a Direita): Rola os bits do destino para a direita as
vezes
“vezes” indicadas com todos os dados que “vazarem” pela direita re-entrando
pela esquerda. O flag de carry conterá o valor do último bit rolado.
Shift Arithmetic Right (Deslocamento Aritmético para a Direita): Desloca os
SAR destino, bits do destino para a direita as “vezes” indicadas com o bit de sinal replicado
vezes
no último bit. O flag de carry conterá o valor do último bit deslocado.
SBB destino, Subtract with Borrow (Subtração com Empréstimo): Subtrai a fonte do
fonte
destino, além de subtrair 1 se o flag de carry estiver setado. O resultado é
armazenado no destino.
SHL destino, Shift Logical Left (Deslocamento Lógico para a Esquerda): Desloca os bits
vezes
do destino para a esquerda as “vezes” indicadas com zeros colocados à
direita. O flag de carry conterá o valor do último bit deslocado.
SHR destino, Shift Logical Right (Deslocamento Lógico para a Diretita): Desloca os bits
vezes
do destino para a direita as “vezes” indicadas com zeros colocados à
esquerda. O flag de carry conterá o valor do último bit deslocado.
SUB destino, Subtraction (Subtração): Subtrai a fonte do destino e o resultado é
fonte
armazenado em destino.
TEST destino Test (Testar): Faz um AND lógico entre os operandos, atualizando os flags e
fonte
sem armazenar o resultado.
XCHG destino, Exchange (Troca): Troca o destino pela fonte e vice-versa. Fonte e destino
fonte
podem ser dois registradores ou um registrador e uma posição de memória.
XOR destino, Exclusive Or (OU Exclusivo): faz um OU Exclusivo entre os operandos e
fonte
retorna o resultado no destino.
NOP
–
–
Aft: C,O,P,S,Z
Ind: A
–
todos são
afetados
–
–
Aft: C, O
Aft: C, O
Aft: C, O
Aft: C, O
Aft: C, O, P,
S, Z
Ind: A
Aft: A, C, O,
P, S, Z
Aft: C,O,P,S,Z
Ind: A
Aft: C,O,P,S,Z
Ind: A
Aft: A, C, O,
P, S, Z
Aft: C,O,P,S,Z
Ind: A
–
XCHGpdestino,
Aft: C,O,P,S,Z
Ind: A
11
Obs:
Aft → significa Afetado. Indica quais flags são afetados depois de executada determinada instrução.
Ind → significa Indefinido. Indica quais flags são “setados” indefinidamente (aleatoriamente).
A tabela 3 mostra instruções de quebra ou mudança de seqüência do tipo Jxx.
Tabela 3 – Conjunto de Instruções de Transferência Condicional.
Mnemônico
JA
JAE
JB
JBE
JC
JCXZ
JE
JG
JGE
JL
JLE
JMP
JNA
JNAE
JNB
JNBE
JNC
JNE
JNG
JNGE
JNL
JNLE
JNO
JNP
JNS
JNZ
JO
JP
Significado
Salte se Acima (Jump if Above)
Salte se Acima ou Igual (Jump if Above or Equal)
Salte se Abaixo (Jump if Below)
Salte se Abaixo ou Igual (Jump if Below or Equal)
Salte se Carry (Jump if Carry)
Salte se CX for Zero (Jump if CX Zero)
Salte se Igual (Jump if Equal)
Salte se Maior (Jump if Greater) (COM SINAL)
Salte se Maior ou Igual (Jump if Greater or Equal) (COM SINAL)
Salte se Menor (Jump if Less) (COM SINAL)
Salte se Menor ou Igual (Jump if Less or Equal) (COM SINAL)
Salto Incondicional (Unconditional Jump)
Salte se Não Acima (Jump if Not Above)
Salte se Não Acima ou Igual (Jump if Not Above or Equal)
Salte se Não Abaixo (Jump if Not Below)
Salte se Não Abaixo ou Igual (Jump if Not Below or Equal)
Salte se Não Carry (Jump if Not Carry)
Salte se Não Igual (Jump if Not Equal)
Salte se Não Maior (Jump if Not Greater) (COM SINAL)
Salte se Não Maior ou Igual (Jump if Not Greater or Equal) (COM SINAL)
Salte se Não Menor (Jump if Not Less) (COM SINAL)
Salte se Não Menor ou Igual (Jump Not Less or Equal) (COM SINAL)
Salte se Não Overflow (Jump if Not Overflow) (COM SINAL)
Salte se Não Paridade (Jump if Not Parity)
Salte se Não Sinal (Jump if Not Signed) (COM SINAL)
Salte se Não Zero (Jump if Not Zero)
Salte se Overflow (Jump if Overflow) (COM SINAL)
Salte se Paridade (Jump if Parity)
Condição de Salto
C=0eZ=0
C=0
C=1
C = 1 ou Z = 1
C=1
CX = 0
Z=1
Z=0eS=O
S=O
S <> O
Z = 1 ou S <> O
C = 1 ou Z = 1
C=1
C=0
C=0eZ=0
C=0
Z=0
Z = 1 ou S <> O
S <> O
S=O
Z=0eS=O
O=0
P=0
S=0
Z=0
O=1
P=1
Uma vez apresentadas as diversas instruções reconhecidas pelo microprocessador 8086/88 da Intel, será
exemplificado abaixo um pequeno programa feito no SID utilizando estas instruções, e entendendo passo a passo
o que o programa faz.
ENDEREÇO
0000
0002
0004
0007
0009
000B
MNEMÔNICOS
SUB AX, AX
ADD AX, [BX]
ADD BX, 2
CMP DX, BX
JNS
0002
INT
3
COMENTÁRIOS
Faz AX = 0
Adiciona uma Word apontada por BX em AX
Adiciona 2 à BX
Compara DX com BX
Se DX ≥ BX salta para o endereço 0002
Finaliza o programa
A programação em assembly é feita através de mnemônicos, que são, posteriormente, convertidos em
opcodes pelo montador, que é a linguagem de máquina entendida pelo processador.
12
8. INTERRUPÇÕES
Uma das coisas essenciais que tornam um computador diferente de qualquer outro tipo de máquina feita pelo
homem é sua capacidade de responder a uma imprevisível variedade de trabalhos. O recurso de interrupção
permite ao computador suspender o que estiver fazendo e passar a fazer outra coisa em resposta a uma
interrupção (por exemplo, pressionar uma tecla no teclado). Os processos de interrupções permitem este tipo de
resposta imediata sem ter que desperdiçar tempo de CPU e códigos de programa, verificando todas as possíveis
tarefas paralelas que precisem ser realizadas em um determinado momento.
8.1 Interrupções por Hardware Interno
Interrupções internas são geradas por certos eventos que ocorrem durante a execução de um programa. Estes
tipos de interrupções são gerenciados, na sua totalidade, pelo hardware e não é possível modificá-las. Um
exemplo claro deste tipo de interrupção é a que atualiza o contador do clock interno do computador, o hardware
chama esta interrupção muitas vezes durante um segundo.
Não é permitido ao programador gerenciar diretamente esta interrupção, uma vez que não se pode
controlar a hora atualizada por software. Mas o programador pode usar seus efeitos no computador para o seu
benefício, por exemplo para criar um virtual clock atualizado continuamente pelo contador interno de clock. Para
tanto, é necessário apenas ler o valor atual do contador e o transformar num formato compreensível pelo usuário.
8.2 Interrupções por Hardware Externo
Interrupções externas são geradas através de dispositivos periféricos, tais como teclados, impressoras, placas de
comunicação, entre outros. São também geradas por co-processadores. Não é possível desativar interrupções
externas.
Estas interrupções não são enviadas diretamente para a CPU, mas, de uma forma melhor, são enviadas
para um circuito integrado cuja função exclusiva é manusear este tipo de interrupção. O circuito, chamado
PIC8259A, é controlado pela CPU através de uma série de comunicação chamada paths.
8.3 Interrupções por Software
Interrupções por software podem ser ativadas diretamente por programas assembly, invocando o número da
interrupção desejada com a instrução INT. O uso das interrupções facilita bastante a criação dos programas,
tornando-os menores. Além disso, é fácil compreendê-las e geram boa performance.
Estes tipos de interrupções podem ser separados em duas categorias: Interrupções do Sistema
Operacional DOS e interrupções do BIOS. A diferença entre ambas é que as interrupções do sistema operacional
são mais fáceis de usar, mas também são mais lentas, uma vez que acessam os serviços do BIOS. Por outro lado,
interrupções do BIOS são muito mais rápidas, mas possuem a desvantagem de serem parte do hardware, o que
significa serem específicas à arquitetura do computador em questão.
A escolha sobre qual o tipo de interrupção usar irá depender somente das características que deseja dar
ao seu programa: velocidade (use BIOS), portabilidade (use DOS).
8.4 Principais Interrupções
BIOS:
Interrupção 16h – serviço 0
MOV AH, 0
INT 16H
13
função: leitura do teclado sem ecoar na tela. Na saída, AL contém o código do caractere que foi digitado. Se AL
= 0 então foi pressionada uma tecla especial cujo código estará em AH = SCAN CODE.
Interrupção 10h – serviço 2
MOV AH, 2
MOV DH, linha
MOV DL, coluna
MOV BH, 0 ; pagina de video.
INT 10H
função: posiciona o cursor.
Interrupção 10h – serviço 6
MOV AH, 6
MOV AL, numero de linhas a rolar
MOV CH, linha superior esquerdo
MOV CL, coluna superior esquerdo
MOV DH, linha inferior direito
MOV DL, coluna inferior direito
MOV BH, atributo
INT 10H
função: limpa a tela.
DOS:
Interrupção 21h – serviço 1
MOV AH, 1
INT 21H
função: leitura do teclado com eco na tela. O caractere lido está em AL, se AL = 0, deve repetir a leitura (tecla
especial).
Interrupção 21h – serviço 9
MOV AH, 9
MOV DX, offset string
INT 21H
função: imprime na tela uma string que inicia no endereço apontado por DX e vai até encontrar um "$".
Interrupção 21h – serviço 2
MOV AH, 2
INT 21H
função: escreve o caractere que está em DL na tela.
9. BIBLIOGRAFIA
1. Lance A. Leventhal - 8080/8085 Assembly Language Programming, Osborne/McGraw-Hill, Berkeley,
California, 1979.
2. Lance A. Leventhal and Winthrop Saville - 8080/8085 Assembly Language Subroutines,
Osborne/McGraw-Hill, Berkeley, California, 1983.
3. Antonio C. J. F. Visconti - Microprocessadores 8080 e 8085 : Software, Livros Érica Editora Ltda., Vol.
2, São Paulo, 1983.
4. Intel Corporation - MCS-85 User's Manual, 1981.
5. Intel Corporation - 8080/8085 Assembly Language Programming Manual, 1981.
14

Documentos relacionados