Pontifícia Universidade Católica do Rio Grande do Sul
Microprocessador Intel 8086
Disciplina: Arquitetura de Computadores I
Professor: Eduardo Augusto Bezerra
Alunos: Fabiano Klein
Franklin Mota Amormino
Rodrigo Belagamba de Moraes
Tiago Scapin
Índice
ÍNDICE ... 2
ARQUITETURA DO MICROPROCESSADOR INTEL 8086 ... 3
INTRODUÇÃO ... 3
1 DESCRIÇÃO GERAL DA ARQUITETURA DO PROCESSADOR 8086 ... 4
2 REGISTRADORES ... 6
2.1 REGISTRADORES DE SINALIZADORES (FLAGS) ... 7
3 ENDEREÇO FÍSICO DE MEMÓRIA E SEGMENTAÇÃO ... 7
3.1 EXEMPLO DE ENDEREÇAMENTO ... 7
4 MODOS DE ENDEREÇAMENTO ... 8
5 CONJUNTOS DE INSTRUÇÕES ... 9
5.1 TRANSFERÊNCIA ... 9
5.2 ARITMÉTICAS ... 9
5.3 LÓGICAS ... 10
5.4 DIVERSOS ... 10
5.5 SALTOS (GERAIS) ... 10
5.6 SALTOS SEM SINAL ... 10
5.7 SALTOS COM SINAL (INTEIRO) ... 11
6 DESCRIÇÃO GERAL DO NETWIDE ASSEMBLER (NASM) ... 11
6.1 ESCRITA DE PROGRAMAS ... 11
6.2 COMPILANDO COM O NASM ... 11
6.3 ESTRUTURA DE UM PROGRAMA NASM ... 12
6.4 CARACTERÍSTICAS PRINCIPAIS DO NASM ... 13
Arquitetura do microprocessador Intel 8086
Introdução
Neste trabalho iremos fazer uma breve descrição do processador Intel 8086 que surgiu em 1978, vindo de uma linha de desenvolvimento da qual se destaca os processadores 8080 e 8085, datados de 1974, e com os quais o 8086 procurou manter uma certa compatibilidade.
Iremos abordar importantes tópicos referentes a arquitetura do 8086, entre eles:
registradores, endereçamento físico de memória, modos de endereçamento e o conjunto instruções usadas pelo 8086.
1 Descrição Geral da Arquitetura do processador 8086
O microprocessador 8086 da Intel é um microprocessador de 16 bits, de forma que sua unidade lógica e aritmética, os seus registradores internos, e a maior parte das suas instruções foram projetados para trabalhar com palavras de 16 bits. Além disso, o 8086 tem um barramento de dados de largura 16 bits, ou seja, pode ler e escrever na memória ou nos portos de E/S utilizando 16 bits de uma só vez. O barramento de endereços é de 20 bits, de forma que o 8086 pode endereçar 1MB (2²°) posições de memória. Cada uma destas posições de memória é ocupada por um Byte.
A arquitetura do 8086 pode ser organizada em duas unidades distintas: a BIU (Bus Interface Unit) e a EU (Execution Unit). A BIU envia endereços para o barramento de endereços, lê instruções da memória, lê e escreve dados nas portas e na memória.
Assim, a BIU é a unidade responsável por todas as transferências de dados e endereços através dos barramentos. Por sua vez, a EU diz á BIU onde é que há de ir buscar instruções ou dados, decodifica e executa as instruções.
O processador 8086 de 16 bits foi lançado em junho de 1978 e operava a 4,77MHz.
Para o seu primeiro microcomputador, a IBM resolveu usar o 8088 por dois motivos:
manter os custos do PC reduzidos e manter a compatibilidade com chips periféricos. é que o 8088 aceitava um barramento interno de 16 bits (como o 8086), mas seu barramento externo era de 8 bits. O processador 8088 foi implementado com 29.000 transistores e compactado num pacote de 40 pinos.
O estudo da arquitetura do 8086 permite entender a arquitetura dos processadores mais modernos. O modelo de programação básico é muito similar aos processadores mais modernos e todos os recursos em nível de aplicativos, como registradores, tipos de dados e modo de endereçamento, são extensões do conjunto de recursos do 8086 original.
No diagrama de blocos da figura abaixo estão ilustrados os componentes principais do microprocessador 8086: registradores, unidade lógica e aritmética e os barramentos.
Destaca-se também a interface com a memória, com sua unidade somadora e o sistema de controle de execução.
2 Registradores
O 8086 possui 1 registrador de flags, 4 registradores de endereço, 4 registradores de segmento 4 registradores de dados, todos de 16 bits.Os registradores de dados são compostos de dois registradores de 8 bits, os quais correspondem a parte baixa “L” e a parte alta “H” do registrador 16 bits que é representado pela letra “X”.
Classificação dos registradores:
Registradores de Dados
Ax Registrador Acumulador Bx Registrador Base Cx Registrador Contador Dx Registrador de Dados Al Acumulador de 8 bits Ah Parte alta do registrador Ax Bl Parte baixa do registrador Bx Bh Parte alta do registrador Bx Cl Contador de 8 bits
Ch Parte alta do registrador Cx DL Parte baixa do registrador Dx Dh Parte alta do registrador Dx
Registradores de Segmentos
DS Registrador de Segmento de dados ES Registrador de Segmento extra SS Registrador de Segmento de pilha CS Registrador de Segmento de código
Registradores de índice
SI Registrador índice fonte DI Registrador de índice destino
Registradores Apontadores
BP Registrador apontador da base IP Registrador Apontador de Instrução SP Registrador Apontador de Pilha
Registradores Sinalizadores F Registrador de flags
2.1 Registradores de sinalizadores (Flags)
Indica o estado processador em cada instrução, onde cada bit representa uma informação individualmente. No total existem 9 flags, 6 de sinal de estado, 3 de controle, e os outros sete restantes não tem função alguma.
Flags de estados
Carry Flag CF Indicador de "vai-um"
Parity Flag PF Indicador de número PAR de 1's no byte inferior Auxiliary Carry AF Indicador de "vai-um" para operações em BCD Zero Flag ZF Indicador de "zero" na última operação
Sign Flag SF Indicador de resultado negativo Overflow Flag OF Indicador de erro de transbordamento
Flag de controle
Trap flag TF Quando TF=1 após uma interrupção TF=0 Interruption Flag IF Habilita o uso de interrupções
Direction Flag DF Decremento do endereço de memória
3 Endereço físico de memória e Segmentação
A memória do 8086 possui 20 bits de endereçamento na memória, ou seja 1MByte de posições endereçáveis, porém o 8086 opera apenas com registradores de 16 bits, para que seja possível endereçar 20 bits com 16, surge a idéia da segmentação. Segmento é um bloco de memórias com 64Kbytes de posições consecutivas.
O endereço físico de memória de 20 bits é o resultado da soma de um registrador de segmento (deslocado de 4 bits para a esquerda) com um deslocamento de 16 bits. O registrador de segmento e a maneira como o deslocamento é calculado dependem do tipo de referência à memória utilizado.
Uma posição de memória é dada pelo endereço do segmento mais um deslocamento (offset), o cálculo feito é mostrado abaixo:
3.1 Exemplo de endereçamento
Dado o endereço lógico: 8350:0420h
reconhece-se: segmento nº. 8350h
deslocamento 0420h o endereço físico vale:
83500h -> desloca-se uma casa hexa (4 casas binárias)
8 3 5 0 | 0 8 3 5 0 CS (base) <- endereço lógico
Bits 19 4 3 0 15 0
+ 0 4 2 0 0 4 2 0 IP (offset)
15 0 15 0
8 3 9 2 0 <- endereço físico para a memória
19 0
4 Modos de endereçamento
Os modos de endereçamento, juntamente com os seus respectivos significados :
Modo Significado
Imediato: Operando na instrução Registrador: Operando em registrador
Direto: Operando na memória, endereçado por deslocamento contido na instrução
Registrador indireto: Operando na memória, endereçado por deslocamento contido em registrador
Indexado (ou base): Operando na memória, endereçado pela soma do conteúdo do registrador de índice (ou base) com o deslocamento contido na instrução
Base e indexado com deslocamento:
Operando na memória, endereçado pela soma do conteúdo do registrador base e com o deslocamento contido na instrução
O endereço final de um operando é formado pela soma do registrador de segmento com o endereço efetivo fornecido pelo modo de endereçamento. Exemplo de modo de e Endereçamento usando a instrução ADD:
Imediato: ADD CH,5F
Registrador: ADD BX,DX
Direto: ADD WVAR,BX (WVAR é uma referência a
memória)
Registrador indireto: ADD CX,[BX]
Indexado (ou base): ADD [SI+6],AL
Base e indexado com deslocamento: ADD [BX+DI+5],DX
O endereço do operando em negrito corresponde ao modo de endereçamento referenciado.
Os modos de endereçamento não podem ser usados livremente combinados a qualquer instrução do processador. A maior parte das instruções só aceita alguns dos modos apresentados acima. Deve ser verificado cuidadosamente quais modos são válidos para uma dada instrução.
5 Conjuntos de Instruções
5.1 Transferência
Nome Comentário Sintaxe
MOV Mover (copiar) MOV Dest,Source
XCHG Troca XCHG Op1,Op2
STC Seta Carry STC
CLC Limpa Carry CLC
CMC Complementa Carry CMC
STD Seta Direção STD
CLD Limpa Direção CLD
STI Seta Interrupção STI
CLI Clear Interrupção CLI
PUSH Empilha na pilha PUSH Source
PUSHF Empilha flags PUSHF
PUSHA Empilha os registradores gerais PUSHA
POP Desempilha da pilha POP Dest
POPF Desempilha flags POPF
POPA Desempilha os registradores gerais POPA
CBW Converte byte para Word CBW
CWD Converte word para Double CWD
CWDE Conv word para extended double CWDE
IN Input IN Dest, Port
OUT Output OUT Port, Source
5.2 Aritméticas
Nome Comentário Sintaxe
ADD Adiciona ADD Dest,Source
ADC Adiciona com Carry ADC Dest,Source
SUB Subtrai SUB Dest,Source
SBB Subtrai com borrow SBB Dest,Source
DIV Divisão (sem sinal) DIV Op
IDIV Divisão inteira com sinal IDIV Op
MUL Multiplicação (sem sinal) MUL Op
IMUL Multiplicação inteira com sinal IMUL Op
INC Incrementa INC Op
DEC Decrementa DEC Op
CMP Compara CMP Op1,Op2
SAL Deslocamento aritimético para esquerda SAL Op,Quantity SAR Deslocamento aritimético para direita SAR Op,Quantity RCL Girar para esquerda com Carry RCL Op,Quantity RCR Girar para direita com Carry RCR Op,Quantity
ROL Girar para esquerda ROL Op,Quantity
ROR Girar para direita ROR Op,Quantity
5.3 Lógicas
Nome Comentário Sintaxe
NEG Negação (complemento de 2) NEG Op
NOT Inverte cada bit NOT Op
AND and lógico AND Dest,Source
OR or lógico OR Dest,Source
XOR or exclusivo lógico XOR Dest,Source
SHL Deslocamento lógico para esquerda SHL Op,Quantity SHR Deslocamento lógico para direita SHR Op,Quantity
5.4 Diversos
Nome Comentário Sintaxe
NOP Sem operação NOP
LEA Carrega o endereço efetivo LEA Dest,Source
INT Interrupção INT Nr
5.5 Saltos (gerais)
Nome Comentário Sintaxe
CALL Chama sub-rotina CALL Proc
JMP Salta JMP Dest
JE Salta se Igual JE Dest
JZ Salta se Zero JZ Dest
JCXZ Salta se CX for Zero JCXZ Dest
JP Salta se há paridade par JP Dest
JPE Salta se há paridade par JPE Dest
RET Return para sub-rotina RET
JNE Salta se não é Igual JNE Dest
JNZ Salta se não é Zero JNZ Dest
JECXZ Salta se ECX for Zero JECXZ Dest
JNP Salta se não há paridade JNP Dest
JPO Salta se há paridade impar JPO Dest
5.6 Saltos sem sinal
JÁ Salta se maior JA Dest
JAE Salta se maior ou igual JAE Dest
JB Salta se menor JB Dest
JBE Salta se menor ou igual JBE Dest
JNA Salta se não é maior JNA Dest
JNAE Salta se não é maior ou igual JNAE Dest
JNB Salta se não é menor JNB Dest
JNBE Salta se não é menor ou igual JNBE Dest
JC Salta se há Carry JC Dest
5.7 Saltos com sinal (Inteiro)
JG Salta se maior JG Dest
JGE Salta se maior ou igual JGE Dest
JL Salta se menor JL Dest
JLE Salta se menor ou igual JLE Dest
JNG Salta se não é maior JNG Dest
JNGE Salta se não é maior ou igual JNGE Dest
JNL Salta se não é menor JNL Dest
JNLE Salta se não é menor ou igual JNLE Dest
JO Salta se há Overflow JO Dest
JNO Salta se não há Overflow JNO Dest
JS Salta se há sinal (= negativo) JS Dest
JNS Salta se não há Sign (= positivo) JNS Dest
6 Descrição geral do Netwide Assembler (NASM)
A partir daqui iremos abordar os principais aspectos e funcionalidades do NASM, um montador (assembler) 80x86 feito para portabilidade e modularidade. Suporta uma grande variedade de arquivos objeto incluindo Linux e NetBSD/FreeBSD a.out, ELF, COFF, Microsoft 16-bit .obj e Win32. Também gera arquivos binários simples. Sua sintaxe foi desenvolvida para ser simples e de fácil compreensão, similar ao da Intel, porém menos complexa. Suporta Pentium, P6, MMX, 3DNow!, SSE e SSE2 opcodes, e tem um forte apoio para macros. O NASM possui também um disassembler.
6.1 Escrita de Programas
O processo de escrita de programas típico é constituído por um conjunto de passos (edição, assemblagem e execução), que se esquematizam a seguir. Este conjunto de passos é sempre executado para qualquer programa que se pretenda criar.
1º Passo: criar o programa fonte, usando um editor de texto.O ficheiro deverá ter extensão “asm”.
2º Passo: converter o programa fonte para código-máquina usando o NASM. Verificar se há erros indicados pelo NASM, se houver, corrigi-los. (ver Compilando com o NASM)
3º Passo: executar o programa; verificar se o resultado é o esperado, caso contrário o programa ainda contém erros que devem ser corrigidos.
6.2 Compilando com o NASM
nasm -f <formato> <nome_do_arquivo> [-o <saída>]
Linux), o comando seria:
nasm -f elf Exemplo.asm
o objeto de saída seria Exemplo.o, é neste caso que vale o -o, podemos definir o nome do arquivo de saída, por exemplo:
nasm -f elf Exemplo.asm -o Exemplo.com
Caso queiramos que o NASM retorne em um arquivo os códigos hexadecimais gerados, seria utilizando então o '-l', por exemplo:
nasm -f coff Exemplo.asm -l Exemplo.lst
Temos também a possibilidade de gerar dentro de nossos códigos "pistas" para que possamos debbugar um código após estar compilado, assim utilizamos o '-g' para tal propósito, veja o exemplo:
nasm -f elf Exemplo.asm -o Exemplo.com -g
Pronto, o código executável gerado possui nossas pistas para DEBUG. Uma utilidade muito legal é podermos, quando criamos nossos códigos cheios de erros, de fazer com que o NASM envie a saída de erros do console para um arquivo específico.
Veja o exemplo abaixo em que os erros do programa Exemp01.asm são enviados para o arquivo QuantosErros.err:
nasm -E QuantosErros.err -f obj Exemp01.asm
Se ao invés de '-E' usássemos '-s' teríamos a saída na STDOUT, a saída padrão.
Como em C/C++ e o no GCC, temos a possibilidade de que o NASM nos mostre Warnings, ou seja, códigos ou variáveis que talvez tenham sido utilizadas de forma equivocada (no caso do gcc o parametro é -Wall), para isso utilizamos o '-w' para que esses "Warning's" sejam gerados.
6.3 Estrutura de um programa NASM
Os programas executáveis serão do tipo .COM, ficheiros em binário puro, os quais devem ser carregados e executados a partir do endereço 100h. Para o efeito, os programas devem começar com a directiva org 100, seguidos de três secções (text, data e bss) segundo o esquema abaixo:
ficheiro fonte: teste.asm
Estas secções podem ser colocadas por outra ordem (ao criar o programa executável, o NASM acaba sempre por colocar a “section .text” no início).
As secções são opcionais: um programa pode conter apenas algumas delas – se um programa não precisar de dados inicializados a “section .data” será omitida; se não precisar de dados não inicializados, então a “section .bss” não existirá. No entanto, não faz muito sentido que não exista a “section .text”, pois nesse caso o programa não fará nada.
6.4 Características principais do NASM
Comentários: começam por “;” e tudo o que lhe seguir é ignorado pelo assembler.
Podem ser aplicados a uma linha inteira ou apenas a parte. É importante comentar as partes do programa cujo significado seja menos evidente, como sejam os algoritmos utilizados, significado das variáveis, etc.
Maiúsculas/minúsculas: o NASM é case-sensitive, ou seja, distingue entre elementos escritos em maiúsculas ou minúsculas. Esta regra não é universal, aplicando- se a nomes (constantes, variáveis), mas não a instruções, diretivas ou comentários. Por exemplo, a instrução “mov” pode ser escrita “Mov” ou “MOV”, pois é uma palavra reservada da linguagem, mas uma variável que tenha sido declarada com o nome “foo”
não pode ser referenciada por “FOO”, caso contrário o NASM indica que a variável não existe.
Linha de código: uma linha típica de código em NASM tem a forma:
<label>: <instrução> , <operandos> ;comentário em que todos os elementos são opcionais i.e., uma linha de código pode não conter alguns deste elementos:
<label>: indica um local para onde uma instrução de salto pode saltar
Obs.: a utilização dos dois pontos é opcional, mas é mais seguro utilizá-los. Se não forem usados o NASM pode considerar que uma instrução que foi escrita por engano é uma label, não indicando erro, mas fazendo com que o programa não trabalhe corretamente
<operandos> constantes, variáveis, registros, etc, a que a instrução faz referência Exemplo:
mov al , 5 ;coloca o valor inteiro 5 no registro al
cont: dec al ;define a label “cont” e decrementa de uma unidade o valor do registro al
jnz cont ;salta (jump) para a linha anterior (aonde foi definida a label “cont”) se não ;resultou zero da última operação aritmética realizada (que foi “dec al”)