AC-Intel

Propaganda
Escola Superior de Tecnologia e Gestão
Instituto Politécnico de Leiria
Microprocessador Intel 8086
Apontamentos de
Arquitectura de Computadores
Arquitectura de Computadores / ESTG-IPL
1 - MICROPROCESSADOR 8086
Motivação
Embora já hajam microprocessadores derivados do 8088/8086 muito mais evoluídos
(80188, 80186, 80286, 8386 e 80486), vai-se começar um estudo de base pelo 8086
da Intel devido a duas razões essenciais:
- foi aquele que deu origem ao aparecimento em 1978 do chamado PC através do seu
uso pela IBM no chamado IBM PC/XT;
- o seu conjunto de instruções continua totalmente compatível, inclusivé com o
Pentium.
ESTRUTURA DE UM MICROCOMPUTADOR BASEADO NO 8086
MICROCOMPUTADOR
Sistema constituído basicamente por uma unidade de processamento central (CPU),
memória e portos. A respectiva interligação é feita por intermédio de 3 barramentos:
barramento de endereços, de controlo e de dados.
MICROCOMPUTADOR BASEADO NO 8086
Se o pino MN / MX permanecer ao nível lógico "0", o 8086 opera no seu modo
máximo; se o nível lógico for "1" então a operação será no modo mínimo.
É de notar que o 8088 apenas difere do 8086 no barramento de dados, que é de 8 bits.
(Figura 1- "Pin-out" e operação em modo máximo.)
(Figura 2- operação em modo mínimo.)
CPU
Unidade de Processamento Central - microprocessador.
RAM
"Random-Acess Memory" - memória volátil para escritas/leituras.
ROM
"Read-Only Memory" - memória não volátil para leituras.
Portos
Portos para ligação de dispositivos em paralelo (p. ex. uma PRN) e em série (p. ex.
um rato) e também a ligação de teclados e CRTs.
BUS de controlo
No modo mínimo este é constituído basicamente pelos sinais:
2
Arquitectura de Computadores / ESTG-IPL
M / IO - permite escolher entre operações de memória e de I/O;
RD - vai a "0" para operações de leitura;
WR - vai a "0" para operações de escrita.
No modo máximo os sinais de controlo vão codificados nas linhas de estado S 0 , S1,
S2.
BUS de endereços/dados
À saída do P este barramento tem 20 linhas (16 linhas de endereços multiplexadas
nas 16 linhas de dados AD0-AD15 em conjunto com 4 linhas de endereços adicionais
A16-A19).
O 8086 é um P de 16 bits porque tem um BUS de dados de 16 bits.
O 8086 tem a capacidade de endereçar até 1 Mbyte de memória pois o BUS de
endereços é de 20 bits.
Latch
Quando o sinal ALE ("Address Latch Enable") vai a "1" o endereço é colocado nas
saídas das "latches" e portanto o barramento ADDR/DATA já pode ser usado para
escrita/leitura de dados. Fazendo-se esta desmultiplexagem, evita-se a existência de
pinos adicionais e a cápsula do P não necessita de ser maior.
Transceiver
Costituído por "buffers tri-state" bidireccionais e tem como objectivo fornecer
corrente para regenerar os níveis lógicos do barramento de dados que se vão
degradando à medida que se interligam mais dispositivos.
A bidireccionalidade é escolhida pelo P através do sinal DT / R (transmite
dados/recebe dados).
A característica "tri-state" é seleccionada pela linha DEN quando se pretende
colocar o BUS de dados em alta impedância, como p. ex. quando o P está a
exteriorizar os 16 bits menos significativos de um endereço no BUS ADDR/DATA.
Controlador externo
É usado no modo máximo de operação do 8086 para gerar um conjunto mais
completo de sinais de controlo.
Gerador de relógio
Usa um cristal para produzir um sinal (CLK) com uma frequência de relógio estável
que faz avançar o P de instrução em instrução.
O sinal RESET inicializa o sistema colocando o P no endereço FFFF0h para ir
buscar a sua próxima instrução.
O sinal READY quando está a "1" origina que o 8086 opere normalmente. Se estiver a
"0" no instante certo, são inseridos um ou mais "wait states" no ciclo de máquina
(aumenta o período de tempo desde endereços estáveis a dados válidos e portanto as
3
Arquitectura de Computadores / ESTG-IPL
memórias poderão ter tempos de acesso maiores e consequentemente serão mais
baratas).
ARQUITECTURA INTERNA
O P divide-se internamente em duas unidades separadas que funcionam de forma
independente: BIU e EU.
(Figura 3 - arquitectura interna do 8086)
BIU ("BUS INTERFACE UNIT")
- retira instruções da memória, lê operandos, escreve
resultados;
Fila de instruções
Grupo de registos tipo FIFO (First-In-First-Out) que podem comportar até 6 Bytes de
instruções retiradas antecipadamente ("prefetched") da memória. Isto servirá para
diminuir o tempo de execução dos programas sobrepondo ("overlapping") a retirada
de instruções da memória com a respectiva execução - "pipelining".
Somador dedicado
Usado para calcular endereços físicos de 20 bits.
Lógica para o BUS de controlo
Gera todos os sinais do barramento de controlo, tais como M / IO , RD e WR .
Registos de segmento
O 8086 pode endereçar até 1 Mbyte de memória, contudo de uma só vez apenas pode
endereçar 254 Kbytes em blocos de 64 Kbytes (segmentos)
CS ("code segment register") - aponta para o segmento de código;
SS ("stack segment register") - aponta para o segmento de pilha;
DS ("data segment register") - aponta para o segmento de dado;
ES ("extra segment register") - aponta para o segmento de dados extra.
Nota:
Cada um destes registos contém os 16 bits mais significativos do endereço físico
correspondente a cada um dos segmentos.
EU ("EXECUTION UNIT")
- descodifica e executa as instruções que o BIU retira da
memória.
Unidade aritmética e lógica ALU
Responsável por:
- operações aritméticas e lógicas;
- manutenção do estado do P e das "flags" de controlo;
- manipulação dos registos de uso geral e dos operandos das instruções.
Registos de uso geral
4
Arquitectura de Computadores / ESTG-IPL
Os registos de 16 bits de uso geral AX, BX, CX, DX podem ser usados como registos
de 8 bits (AH, AL; BH, BL; CH, CL; DH, DL), que representam respectivamente o
byte mais e menos significativo do correspondente conteudo.
Podem ser usados para funcionalidades genéricas, contudo têm utilizações especificas
que os caracterizam.
AX ("Accumulator Register") - é assumido por algumas instruções como p. ex. IN,
OUT, MUL, DIV, etc..
BX ("Base Register") - é o único registo que além de ser de uso geral, também pode
ser usado para endereçamento de memória.
CX ("Counter Register") - é utilizado como contador em instruções como p. ex.
SHIFT, ROTATE, LOOP.
DX ("Data Register") - é utilizado em instruções como p. ex. MUL e DIV.
Registos de pilha
São registos de 16 bits que se usam para aceder a dados no segmento de pilha.
SP ("Stack Pointer Register") - é usado como "offset" ou deslocamento a partir de um
endereço corrente no segmento de pilha em instruções como
p. ex. POP e PUSH.
BP ("Base Pointer Register") - é usado como "offset" ou deslocamento a partir de um
endereço corrente no segmento de pilha em instruções que o
modo de endereçamento baseado.
Registos de índice
São registos de 16 bits que se usam para endereçamentos indexados.
SI ("Source Index Register") - é usado no modo de endereçamento indexado e utilizase em instruções de processamento de "strings" no segmento
de dados para indicar o endereço fonte.
DI ("Destination Index Register") - é usado no modo de endereçamento indexado e
utiliza-se em instruções de processamento de "strings" no
segmento extra de dados para indicar o endereço destino.
Registo das "flags"
Este registo de 16 bits contém o estado das várias "flags".
15
14
13
12
11
10
9
8
7
6
OF
DF
IF
TF
SF
ZF
5
4
AF
3
2
PF
1
0
CF
AF ("Auxiliary Carry Flag") - está a "0" e só é colocada a "1" se há um "carry" do
"nibble" menos significativo no mais significativo ou um
"borrow" do "nibble" mais significativo no menos
significativo relativamente nos 8 bits de um registo de 16 bits.
Esta "flag" é usada em instruções aritméticas BCD.
5
Arquitectura de Computadores / ESTG-IPL
CF ("Carry Flag") - vai a "1" se há um "carry" numa adição ou um "borrow" numa
subtracção.
OF ("Overflow Carry Flag") - está a zero e só vai a "1" se acontecer algum
"overflow" após uma instrução aritmética, isto é, quando o
tamanho do resultado excede a capacidade do local de destino.
SF ("Sign Flag") - está a zero e só vai a "1" se o bit mais significativo de um resultado
for "1".
PF ("Parity Flag") - vai a "0" quando um resultado tem paridade "even" e vai a "1"
quando a paridade for "odd".
ZF ("Zero Flag") - está a "0" se um resultado for não nulo e vai a "1" se for nulo.
O 8086 tem 3 "flags" adicionais para controlo de bits que podem ser alteradas
pelo programador:
DF ("Direction Flag") - colocando-a a "0" possibilita-se que as instruções para
"strings" auto-incrementem, caso contrário auto-decrementam.
IF ("Interrupt Flag") - colocando-a a "1" possibilita-se ao 8086 que este reconheça
interrupções externas mascaráveis.
TF ("Trap Flag") - colocando-a a "1" coloca-se o 8086 no modo passo-a-passo,
gerando uma interrupção após a execução de cada instrução.
Assim o utilizador pode fazer uma rotina de serviço para que
após cada interrupção se visualize o conteúdo de registos e
posições de memória desejados - "debugging".
SEGMENTAÇÃO DE MEMÓRIA
O 8086 pode endereçar até 1 Mbyte de memória, contudo de uma só vez apenas pode
endereçar 254 Kbytes em blocos de 64 Kbytes (segmentos):
segmento de código
segmento de pilha
segmento de dados
segmento de dados extra
Em qualquer instante que o 8086 acede à memória, é calculado no BIU o necessário
endereço físico de 20 bits a partir do valor base (ou de início) de um segmento e de
um "offset", pois o P não tem registos de 20 bits.
Os 4 segmentos da memória podem eventualmente estar totalmente sobrepostos,
parcialmente sobrepostos, contíguos ou disjuntos.
(Figura 4 - disposição dos segmentos de forma disjunta)
(Figura 5 - exemplos de cálculo de endereços físicos)
Endereço físico no segmento de código
6
Arquitectura de Computadores / ESTG-IPL
Cada uma das instruções de um programa encontram-se localizadas no segmento de
código, num endereço calculado a partir do par de registos CS:IP.
Endereço físico no segmento de pilha
É calculado a partir do par de registos SS:SP, em instruções de pilha como p. ex.
PUSH e POP ou então a partir do par de registos SS:BP, no caso de se usar um
endereçamento baseado.
Endereço físico no segmento de dados
É calculado a partir dos pares de registos DS:SI, DS:DI ou DS:BX.
Endereço físico no segmento extra de dados
É calculado a partir do par de registos ES:DI.
Nota:
Para representar endereços físicos têm-se 2 alternativas (p. ex. o endereço 5FFE0h
pode ser representado também por 5000:FFE0h).
PROGRAMAÇÃO EM ASSEMBLER
PORQUÊ PROGRAMAR EM ASSEMBLER?
Permite uma maior aproximação à máquina (o código aproxima-se do código de
máquina);
Os programas em assembler ocupam menos espaço (cerca de 10 vezes menos que os
equivalentes em C ou Pascal);
Os programas em assembler são mais rápidos (2 a 3 vezes mais rápidos que os
equivalentes em C ou Pascal).
Existe a possibilidade de programas elaborados em alto nível usarem pequenas rotinas
feitas em assembler.
DADOS, ENDEREÇOS DE DADOS E DE INSTRUÇÃO
Dados
São números de 8, 16 ou 32 bits, com ou sem sinal, sobre os quais as operações são
imediatas (sem haver descodificação de endereços). Note-se que os caracteres são
representados com números de 8 bits sem sinal por meio de um código ASCII).
Endereços de dados
São endereços que permitem determinar onde se irão buscar os dados a manipular
(são os "offsets" nos segmentos de dados). Estes "offsets" serão o conteúdo de vários
ponteiros para dados (como p. ex. ponteiro para byte - DB, ponteiro para palavra DW, ponteiro para palavra dupla - DD, etc.).
Endereços de instrução
7
Arquitectura de Computadores / ESTG-IPL
São endereços que permitem ir buscar as instruções à memória e são definidos por
etiquetas "Labels"
DIRECTIVAS PARA OS SEGMENTOS
As directivas, tal como o próprio nome indica, são direccionamentos para o assembler
e não são instruções.
Existem dois tipos de directivas para os segmentos:
directivas simplificadas;
directivas "standard".
Directivas simplificadas
Facilitam o controlo dos segmentos e são ideais para "linkar" módulos em assembler
às linguagens de alto nível. No entanto, apenas suportam algumas características de
controlo dos segmentos que o "Turbo Assembler" pode proporcionar.
.DOSSEG - origina um agrupamento dos segmentos num programa em assembler
segundo uma ordem convencionada pela "Microsoft" (alguns programas
não funcionam bem quando se omite esta directiva).
.MODEL - especifica o modelo de memória para um módulo em assembler que use
directivas simplificadas. Os modelos de memória disponíveis são:
Tiny - o código e os dados cabem num mesmo segmento de 64 K (ambos
"near");
Small - o código e os dados cabem em segmentos separados de 64 K
(ambos "near");
Medium - o código pode exceder 64 K e os dados devem caber num
segmento de 64K (código "far", dados "near");
Compact - o código cabe em 64 K e os dados podem exceder (código
"near", dados "far");
Large - o código e os dados podem exceder 64 K, mas nenhum array
de dados singular pode exceder 64 K (ambos "far");
Huge - o código e os dados podem exceder 64 K e os arrays de dados
podem exceder 64 K (ambos "far");
Nota:
"near" e "far" indicam respectivamente que os endereços físicos nos
respectivos segmentos podem ser obtidos a partir de "offsets" ou a partir
de pares "segment:offset".
8
Arquitectura de Computadores / ESTG-IPL
.STACK - define o tamanho da pilha para programas que façam uso dela (é normal
encontrar o tamanho de 200h (512 bytes) para programas não
muito "pesados", como é o caso dos que usam recursividade).
Exemplo:
.STACK 200H
.DATA - define o início do segmento de dados ou do segmento extra de dados.
Exemplo:
.DATA
variavel_x DB 'Ola'
Nota:
Para se aceder a posições de memória nestes segmentos de dados deve-se carregar o
registo DS com o símbolo @data:
mov AX,@data ; para o segmento de dados
mov DS,AX
mov DX,@data ; para o segmento extra de dados
mov ES,DX
.CODE - define o início do segmento de código (diz ao turbo assembler onde deve
colocar as instruções).
Exemplo:
.CODE
Inicio_Codigo:
(...)
Directivas "standard"
São mais complicadas de usar, mas permitem explorar todas as capacidades de
controlo dos segmentos por parte do TASM.
SEGMENT - define o início de um segmento e a "label" que a acompanha é o nome
dado ao segmento.
ENDS - define o fim de um segmento e a "label" que a acompanha é o nome dado ao
segmento.
ASSUME - indica ao TASM a que registo de segmento está atribuído um segmento.
Exemplos:
pilha SEGMENT
DB 200 DUP(?)
pilha ENDS
dados SEGMENT
9
Arquitectura de Computadores / ESTG-IPL
variavel_x DB 'Ola'
dados ENDS
codigo SEGMENT
ASSUME CS:codigo,DS:dados,SS:pilha
(...)
codigo ENDS
OUTRAS DIRECTIVAS
DB ("Define Byte") - usada para declarar uma variável do tipo byte ou então reservar
uma ou mais posições de memória do tipo byte.
Exemplos:
PRECOS DB 49H,98H,29H ;declara um array de 3 ;bytes chamado
PRECOS e inicializa-o ;daquela forma.
NOME DB 'Sergio' ;declara um array de 6 bytes ;com aquele nome
inicializando-o com os ;códigos ASCII das letras do nome
Sergio.
ARMAZENA DB 100 DUP(?) ;reserva 100 bytes ;de memória não
inicializados e dá-lhe ;aquele nome.
ARMAZENA DB 49H DUP(0) ;declara 49h bytes ;inicializados com zeros e
dá-lhe aquele ;nome.
DW ("Define Word") - usada para declarar uma variável do tipo word ou então
reservar uma ou mais posições de memória do tipo word
inicializadas , ou não.
Exemplos:
NUMERO DW 437AH; declara uma variável do ;tipo word cujo nome é
NUMERO e dá-lhe ;aquele valor.
Nota:
Para declarar variáveis existem adicionalmente as directivas:
DD ("Define Double Word");
DQ ("Define Quadword");
DT ("Define Ten Bytes").
END ("End Program") - é colocada na última linha de um programa para o terminar.
O assemblador ignora tudo o que estiver depois dela.
ENDP ("End Program") - é usada em conjunto com o nome de um procedimento para
o terminar. Esta directiva é utilizada em conjunto com a
directiva PROC para delimitar um procedimento.
Exemplo:
10
Arquitectura de Computadores / ESTG-IPL
CALCULO PROC; início do procedimento.
(...)
; instruções do procedimento.
CALCULO ENDP; fim do procedimento.
EQU ("Equate") - usada para dar um nome a um valor ou símbolo. Cada vez que o
assembler encontra o referido nome num programa, ele substitui
o valor ou símbolo com esse nome.
Exemplo:
FACTOR_EXEMPLO EQU 03H ;o valor 03h é substituído por aquele
nome.
EVEN ("Align on Even Memory Address") - é usada para dizer ao assemblador que
incremente o contador de posição (que contém um "offset" num
segmento) para o próximo endereço par, se este ainda não for
par. Assim, possibilita-se uma leitura mais rápida daquilo que
está nesse endereço.
Exemplo:
.DATA
MEDIA DB 9 DUP(?); reserva um array de 9 ;bytes não inicializados e o
contador de ;posição aponta para 0009h.
EVEN; avança para 000Ah.
RESULTADO DW 100 DUP(0); "array" de 100 ;words inicializados a zero
que começa em ;000Ah. Neste endereço a leitura será mais
;rápida.
EXTRN - ver programas multimódulo.
GLOBAL - ver programas multimódulo.
GROUP ("Group-Related Segments") - diz ao assemblador para agrupar os
segmentos num único segmento de 64 Kbytes. Isto permite que o
conteúdo desses segmentos seja acedido a partir do mesmo
endereço de base.
Exemplo:
AGRUPA GROUP CODIGO,DADOS; agrupa os ;segmentos num único.
ASSUME CS:AGRUPA, DS:AGRUPA; os ;registos CS e DS contêm o
endereço base ;do segmento.
INCLUDE - permite inserir um bloco de código fonte, editado num outro ficheiro, no
código fonte actual.
11
Arquitectura de Computadores / ESTG-IPL
Exemplo:
(...)
.CODE
(...)
INCLUDE OUTRO_FICHEIRO.ASM; inclusão ;do código fonte existente
noutro ficheiro.
(...)
LABEL - é usada para dar um nome ao valor actual do contador de posição. Se for
usada para instruções de salto ou de chamada de procedimentos, esta
deve ser especificada como sendo "near" ou "far". Se for usada para
referenciar um ítem de dados deve ser especificada com o tipo de
dados.
Exemplo:
PILHA SEGMENT
DW 100 DUP(0) ; reserva 100 bytes para a pilha.
TOPO_PILHA LABEL WORD; dá um nome à ;proxima posição após a
última palavra na ;pilha.
PILHA ENDS
REPETE LABEL FAR; pode-se fazer um salto ;para esta posição de um
outro qualquer ;segmento.
NAME - ver programas multimódulo.
ORG (“Originate”) - Quando o assemblador começa a a ler um segmento, o contador
de posição vai para 0000h. Com esta directiva pode-se impôr que
esse valor seja outro. O símbolo “$” indica o valor actual dessa
posição.
Exemplos:
ORG 2000H; diz ao assemblador para colocar o ;contador de posição em
2000h.
ORG $+100 ; incrementa o contador de posição ;em 100 a partir do seu valor
actual.
PROC (“Procedure”) - indica o início de um procedimento (ver directiva ENDP).
PUBLIC - ver programas multimódulo.
12
Arquitectura de Computadores / ESTG-IPL
OPERADORES
DUP - permite definir blocos de memória inicializados com um determinado valor
(ver exemplos para a directiva DB).
LENGTH - diz ao assemblador para determinar o número de elementos que existem
num determinado ítem de dados.
Exemplos:
MOV CX,LENGTH STRING1; ao ser executada ;esta linha de código, o
registo CX fica ;com o comprimento da “string” em bytes ou
words.
OFFSET - diz ao assemblador para determinar o “offset” ou deslocamento de uma
variável de dados a partir do início do segmento que a contém.
Exemplos:
MOV BX,OFFSET PRECOS; determina o “offset” ;da variável PRECOS no
segmento de ;dados ;ficando BX com esse valor.
ADD AL,BYTE PTRBX; soma o valor de AL ao ;valor cujo endereço é
dado pelo “offset” ;que está em BX.
PTR (“pointer”) - atribui um tipo específico a uma variável ou “label”.
Exemplos:
INC BYTE PTR BX; incrementa o byte ;apontado por BX.
INC WORD PTR BX; incrementa a palavra ;apontada por BX.
ADD AL,BYTE PTR BX; soma a AL o valor de 8 bits ;cujo endereço é
dado pelo “offset” que ;está em BX.
JMP WORD PTR BX; faz um salto “near”.
JMP DWORD PTR BX; faz um salto “far”.
SHORT - é usado em conjunto com a instrução JMP e diz ao assemblador que
apenas é necessário reservar um byte para essa instrução (em vez de
dois). Contudo, este tipo de saltos apenas atinge “labels”
compreendidas entre -128 bytes e +128 bytes a partir do endereço de
instrução após o salto.
Exemplos:
JMP SHORT NOME_LABEL; faz um salto curto ;(“short”).
13
Arquitectura de Computadores / ESTG-IPL
CONJUNTO DE INSTRUÇÕES
O conjunto de instruções pode ser dividido em 8 grupos consoante, a funcionalidade
destas:
Movimentação de dados
Aritméticas
Lógicas e de deslocamento
Controlo
Derivação
Manipulação de blocos e “strings”
(Tabela 1 - conjunto de instruções do 8086)
MODOS DE ENDEREÇAMENTO
O 8086 tem 12 modos de endereçamento, que podem ser classificados em 5 grupos:
Modo registado e imediato;
Modo de endereçamento de memória;
Modo de endereçamento de portos;
Modo de endereçamento relativo;
Modo de endereçamento implícito.
Modo registado e imediato
Registado - os operandos fonte, os operandos destino ou ambos estão contidos em
registos.
Exemplos:
MOV AL,BL; move o conteúdo de 8 bits de BL ;para AL.
Imediato - os dados na forma de 8 bits ou 16 bits podem ser especificados como
fazendo parte da instrução.
Exemplo:
MOV CX,5062h; move o dado de 16 bits 5062h ;para o registo CX.
Modo de endereçamento de memória
Directo - o endereço efectivo do operando (“offset”) no correspondente segmento é
obtido directamente a partir de um determinado dado, sem envolver
quaisquer registos.
Exemplo:
.DATA
START DW 39FAH
14
Arquitectura de Computadores / ESTG-IPL
(...)
MOV BX,START; move o conteúdo que está no ;endereço de 20 bits
(calculado a partir de ;DS:START.
Indirecto registado - o endereço efectivo de um operando na memória pode ser
obtido a partir de um dos registos de base ou de índice (BX, BP,
SI, DI).
Exemplo:
.DATA
START DW 39FAH
(...)
MOV BX, OFFSET START; BX contém o ;“offset” daquela variável.
MOV CX,BX; move o conteúdo que está no ;endereço de 20 bits
(calculado a partir de ;DS:BX).
MOV AX,ES:BX; move o conteúdo que está no ;endereço de 20 bits
(calculado a partir de ;ES:BX - agora o segmento de dados é o
;extra).
Baseado - o endereço efectivo é calculado a partir de uma contante e dos registos de
base BX ou BP. Quando não se acede à pilha o endereço de 20 bits
é calculado a partir de DS:BX. Quando se acede à pilha esse
endereço é calculado a partir de SS:BP (note-se que BP é o ponteiro
de pilha para o utilizador, enquanto que o SP é o ponteiro de pilha
do sistema, sendo usado em instruções como p. ex. CALL).
Exemplo:
MOV BP,SP; inicializa BP.
MOV -2BP,BX; move o conteúdo de BX para o ;endereço de 20 bits da
pilha (calculado a partir ;de S:BP-2). O operando destino
poder-se-ia representar alternativamente por BP-2 ou por BP2.
Indexado - O endereço efectivo é obtido a partir de uma constante e dos registos de
índice SI ou DI.
.DATA
CARACTERES DB ‘ABCD$’
(...)
15
Arquitectura de Computadores / ESTG-IPL
MOV SI, OFFSET CARACTERES; SI contém o ;“offset” daquela variável
no segmento de ;dados.
MOV AX, 3SI; move-se o caractere ‘D’ para o ;registo AX (é o caractere
que se encontra ;no endereço físico de 20 bits calculado a ;partir
de DS:3+SI ).
Indexado baseado - o endereço efectivo é calculado a partir de uma constante, dos
registos de base (BX, BP) e dos registos de índice (SI, DI).
.DATA
CARACTERES DB ‘ABCD$’
(...)
MOV SI, OFFSET CARACTERES; SI contém o ;“offset” daquela variável
no segmento de ;dados.
MOV BX,1; carrega-se BX com o valor 1.
MOV AX, 2BXSI; move-se o caractere ‘D’ ;para o registo AX (é o
caractere que se ;encontra no endereço físico de 20 bits
;calculado a partir de DS:2+BX+SI ).
De “strings” - neste modo usa-se o registo SI para apontar para o primeiro byte ou
word de uma “string” origem e o registo DI para apontar para o
primeiro byte ou word do destino, quando é utilizada uma
instrução para “strings” (p. ex. MOVS).
Modo de endereçamento de portos
Modo directo - o número da porta é um operando de 8 bits que é utilizado em
conjunto com o acumulador (conseguem-se endereçar até 256
portos).
Exemplo:
IN AL,02; move o conteúdo do porto 2 para o ;registo AL.
Modo indirecto - o número da porta provém de um do registo DX e é utilizado em
conjunto com o acumulador (conseguem-se endereçar até
64Kbytes de portos).
Exemplo:
IN AX,DX; move o conteúdo do porto ;especificado em DX para o registo
AX.
Modo de endereçamento relativo
Neste modo de endereçamento especifica-se um operando como sendo um
deslocamento de 8 bits (positivo ou negativo), que vai ser somado ao valor actual do
IP.
16
Arquitectura de Computadores / ESTG-IPL
Exemplo:
JNC START; se o “carry” for nulo (“not carry”) o ;programa continua a
partir da “label” ;START. Por outras palavras, é somado ao ;IP o
endereço de 8 bits da “label”.
Modo de endereçamento implícito
As instruções que usam este modo não têm operandos.
Exemplo:
CLC; coloca a zero a “carry flag”.
PILHA E CHAMADAS DE FUNÇÕES
Uma pilha é uma estrutura LIFO: o último elemento a entrar é o primeiro a sair.
Existem instruções próprias para colocar e retirar elementos da pilha: PUSH e POP.
O processador acede à pilha por meio do registo SP. Este registo contém o endereço
do último elemento da pilha.
A pilha cresce no sentido decrescente dos endereços.
Topo da Memória
Base da Pilha
Sentido de
Crescimento
da Pilha
Pilha
Topo da Pilha
[SP]
Local de entrada do
próximo elemento
Base da Memória
[0000H]
O registo BP, que indexa o segmento da pilha, não tem qualquer função directa na
manipulação da pilha. Utiliza-se para aceder aos elementos da pilha pela posição que
nela ocupam.
17
Arquitectura de Computadores / ESTG-IPL
Manipulação da pilha
PUSH - Permite colocar na pilha (na posição indicada por SS:SP) uma palavra,
conteúdo de um registo ou posição de memória.
A instrução PUSH decrementa o registo SP em duas unidades e coloca o
operando no novo topo da pilha.
Para colocar o registo FLAGS na pilha existe a instrução PUSHF.
PUSH AX
PUSH CS
PUSH [BX+SI]
PUSHF
POP - Permite retirar a palavra armazenada no topo da pilha, colocando-a no registo
ou posição de memória especificada.
De seguida incrementa o registo SP em duas unidades.
Para carregar o registo FLAGS a partir da pilha existe a instrução POPF.
POP CX
POP DS
POP [DI]
POPF
Chamada de funções
Uma subrotina é uma parte de um programa. O programa chama a subrotina e esta
devolve o controlo ao programa quando acaba.
A chamada de subrotina é um salto com a particularidade de guardar o endereço onde
o programa estava a executar.
A instrução CALL permite chamar uma subrotina.
A rotina pode ser chamada directamente, através de labels dentro do segmento de
código, ou indirectamente, usando-se registos que contêm o endereço da rotina.
O endereço da instrução a ser executada ao retornar da rotina (registo IP) é guardado
na pilha. Nas chamadas FAR, além do IP é necessário guardar também o registo CS.
Assim, numa chamada NEAR, o SP é decrementado de 2 e numa chamada FAR, o SP
é decrementado de 4.
A instrução RET permite fazer o retorno da subrotina, transferindo a execução para a
instrução seguinte à chamada da sub-rotina.
18
Arquitectura de Computadores / ESTG-IPL
O endereço dessa instrução é retirado do topo da pilha e colocado no registo IP, sendo
o registo SP incrementado de 2. No caso de uma chamada far, são retiradas duas
palavras que são colocadas nos registos CS e IP.
Se for especificado um valor imediato como parâmetro da instrução RET, este será
também adicionado ao valor do SP, servindo para libertar parâmetros colocados na
pilha a quando da chamada da rotina.
CALL F1
F1
RET
CALL Subrotina1
CALL BX
CALL double word ptr [SI]
RET
RET 6
Conselhos:
 A documentação é fundamental e deve incluir o fundamental sobre o
comportamento da rotina.
 A rotina deve evitar acessos directos a variáveis globais. Os dados a serem
acedidos devem ser passados como parâmetros
 A rotina deve ser de aplicação geral. Em vez de uma rotina que faça a média
de 100 valores, será mais útil colocar o número de valores como parâmetro.
 A rotina deve ser robusta. Deve prever a ocorrência de casos estranhos, como
por exemplo o número de dados a fazer a média ser 0.
Modelo Black-box - a rotina deve ser conhecida apenas pelas entradas e saídas, sem
necessidade de preocupação em relação ao modo como as mesmas são
tratadas.
Contexto de uma rotina - todas as rotinas utilizam, normalmente variáveis locais.
Essas variáveis podem ser células de memória ou registos.
Se as variáveis forem registos, é necessário salvaguardar os valores que esses
registos continham ao ser chamada a rotina. Esses valores são guardados
(normalmente na pilha) no princípio da rotina e restaurados (por ordem
inversa) no final da rotina.
Exemplo de uma rotina que faz uso dos registos AX, SI e DS:
19
Arquitectura de Computadores / ESTG-IPL
MYPROC
MYPROC
PROC
PUSH AX
PUSH SI
PUSH DS
...
POP DS
POP SI
POP AX
RET
ENDP
SP->
SP->
E.Ret
SP->
Antes
CALL
E.Ret
AX
SI
DS
Contexto
Passagem de parâmetros
Os parâmetros de uma rotina podem ser de entrada, de saída ou entrada /
saída.
Passagem por registo
Utiliza registos para a passagem da informação. Evita passagens pela
memória mas há poucos registos disponíveis.
MOV AX, 100
;nº de elementos
LEA DX,Dados
;Vector dos dados
CALL Media
; Calcula a média
MOV Res,AX
;Guarda-a
Passagem por memória partilhada
Utiliza células de memória fixas para passagem da informação. Poupa os
registos mas tem pouca flexibilidade pois exige a utilização de variáveis
globais.
Passagem pela pilha
este é o modo mais utilizado para passar parâmetros. A pilha é o local onde
são postos os dados e de onde são retirados os resultados.
20
Arquitectura de Computadores / ESTG-IPL
Um exemplo: esta chamada coloca 3 parâmetros na pilha e devolve 2
resultados.
PUSH AX
PUSH BX
PUSH CX
CALL Func1
POP AX
POP DX
SP->
Par1
Par2
Par3
SP->
Parâmetros
Par1
Par2
Par3
E.Ret
DX
SI
SP->
CALL, Contexto
Res2
Res1
E.Ret
Retorno
Para se aceder aos parâmetros dentro da rotina, utiliza-se o registo BP, que
opera sempre no segmento de pilha.
Para se aceder ao 1º parâmetro Par1 do exemplo acima pode-se, por
exemplo, inicializar o BP a SP no início da rotina depois de se guardar o
contexto e utilizar [BP+10] (se se fizessem POPs, retirava-se também o
endereço de retorno!).
Nº de parâmetros de entrada e de saída
 Igual. Neste caso, os parâmetros de saída vão ocupar os lugares dos de
entrada.
 Há mais parâmetros de entrada do que de saída. Neste caso, é necessário
retirar alguns elementos da pilha no retorno.
 Há mais parâmetros de saída do que de entrada. Neste caso, é necessário
mover o endereço de retorno na pilha, para células mais abaixo na memória
de modo a reservar espaço na pilha para os resultados da função.
Outra alternativa é reservar espaço para os parâmetros de saída antes da
chamada:
...
SUB SP, 6;reserva espaço para
; parâmetros de saída
PUSH AX
;parâmetro de entrada 1
PUSH BX
;parâmetro de entrada 2
CALL F1
POP AX
;resultado 1
POP DX
;resultado 2
...
SP->
Par1
Par2
E.Ret
Passagem na sequência da chamada
Colocam-se os parâmetros no meio do código, imediatamente a seguir à
instrução CALL. O endereço inicial dos parâmetros é dado pelo endereço de
21
Arquitectura de Computadores / ESTG-IPL
retorno, que se encontra na pilha. O endereço de retorno real é o endereço da
primeira instrução que aparece depois dos parâmetros.
Este modo de passagem é pouco utilizado.
CALL Funcao1
DB 63, 12, ? ; parâmetros
INC AX
; instrução seguinte
Funcao1 PROC
POP SI
;endereço dos parâmetros
MOV DI, SI ;cálculo do
ADD DI, 3 ;endereço de retorno
PUSH DI
...
Variáveis locais a uma subrotina - Podem guardar-se em células de memória,
registos do processador, espaço reservado na pilha.
Células de memória
Utiliza-se esta opção quando se deseja ter uma variável estática (diferente de
global), i.e., uma variável que se mantém inalterada entre execuções
consecutivas da função.
Registos do processador
O número restrito de registos disponíveis, obriga geralmente ao recurso a
outros lugares para guardar variáveis locais.
Espaço reservado na pilha
Este é o método mais utilizado. O meio de acesso a
estas variáveis é idêntico ao meio de acesso aos
parâmetros passados por pilha.
É aconselhável fazer um mapa da pilha na entrada
da subrotina.
Parâmetros
End.Ret.
Contexto
Variáveis
locais
<- SP
SERVIÇOS DA ROM BIOS
O BIOS (Basic Input Output System) é um conjunto de rotinas (device-drivers)
residentes numa memória ROM que é responsável pela inicialização de periféricos
(tal como teclado, vídeo, disco, etc.) e pela carga do sistema operativo a partir do
disco.
O ficheiro IO.SYS é um dos componentes do DOS e contém extensões ao ROM
BIOS.
As funções disponibilizadas pelo BIOS são acedidas através da instrução INT nn onde
nn é o número da interrupção que se pretende executar. Normalmente, cada número
de interrupção disponibiliza várias funções, sendo a selecção feita através do registo
22
Arquitectura de Computadores / ESTG-IPL
AH. Outros parâmetros necessários para cada função são passados através de outros
registos.
( Tabela 2 - Serviços ROM BIOS )
FUNÇÕES DO DOS
O ficheiro MSDOS.SYS é outro dos componentes do DOS, é responsável pela gestão
de directórios e ficheiros em disco e contém as rotinas de funções do DOS.
Estas funções podem ser invocadas pelo programador através de interrupções. As
principais interrupções de DOS estão listadas na tabela 3.
Destas, a interrupção 21H é de longe a mais útil, fornecendo acesso geral a quase
todas as funções do DOS.
As interrupções de terminação 20H e 27H já não se utilizam, tendo sido substituídas
por funções da interrupção 21H.
As interrupções de acesso absoluto a disco 25H e 26H, podem ser ocasionalmente
necessárias para ultrapassar o interface habitual de acesso a ficheiros de DOS.
Interrupção
20H
21H
25H
26H
27H
Descrição
Terminação normal de programa
Funções de DOS gerais
Leitura absoluta em disco
Escrita absoluta em disco
TSR - Termina e fica residente
Tabela 3 - As cinco principais interrupções de DOS
( Tabela 4 - Funções da interrupção 21H )
Serviço
Terminação com
código de retorno
Standard input de um
caracter com eco
Output de um caracter
para a impressora
Criar um ficheiro
Função
4CH
01H
05H
3CH
Registos
Input
Output
AH=4CH
AL=cod. ret.
AH=01H
AL=caracter
AH=05H
DL=caracter
AH=3CH
CX=atributos
DS:DX ->
caminho para o
ficheiro
se erro:
CF set
AX=código de erro
se não:
CF clear
AX=handle
Tabela 5 - Exemplos de funções da interrupção 21H
PROGRAMAS UNIMÓDULO E MULTIMÓDULO
23
Arquitectura de Computadores / ESTG-IPL
É possível partir um programa grande (unimódulo) em vários módulos ( programa
multimódulo).
Depois de se editar o código fonte só é necessário reassemblar o módulo alterado, em
vez de todas as linhas do programa.
Directiva GLOBAL - Torna as labels associadas disponíveis para vários módulos.
Uma label global deve ter uma directiva GLOBAL em cada módulo onde
seja utilizada.
Uma label global deve ser definida (com DB, DW, PROC, LABEL, etc.)
num e um só dos módulos onde é utilizada.
É necessário informar o Turbo Assembler sobre o tipo de cada label. Os
tipos possíveis são:
ABS, BYTE, DATAPTR, DWORD, FAR, FWORD, NEAR, PROC,
QWORD, Structure Name, TBYTE, UNKNOWN, WORD
O tipo ABS utiliza-se para labels definidas com EQU ou =, i.e., labels
constantes que não estão associadas com um endereço.
Existe um esquema alternativo à directiva global formado pelas directivas
EXTERN e PUBLIC, mantido apenas por questões de compatibilidade. A
directiva PUBLIC utiliza-se no módulo onde é definida a label. A directiva
EXTERN utiliza-se nos módulos onde é também utilizada a label.
MAIN.ASM
...
.DATA
GLOBAL
FinalString: BYTE
FinalString DB
50 DUP (?)
.CODE
GLOBAL
ConcatenateStrings:PROC
ProgramStart:
...
call ConcatenateStrings
...
END ProgramStart
SUB1.ASM
...
.DATA
GLOBAL FinalString: BYTE
.CODE
GLOBAL ConcatenateStrings:PROC
ConcatenateStringsPROC
...
ConcatenateStrings ENDP
END
24
Arquitectura de Computadores / ESTG-IPL
Directiva INCLUDE - Se não se quiser dividir o programa em vários módulos, podese utilizar a directiva INCLUDE.
Quando o Turbo Assembler encontra uma directiva INCLUDE, vai a disco
buscar o ficheiro especificado e trata as linhas aí contidas como se
pertencessem ao módulo corrente.
MAINPROG.ASM
...
.CODE
mov ax, 1
INCLUDE INCPROG.ASM
push ax
...
INCPROG.ASM
mov bx, 5
add ax, bx
...
Programa equivalente:
.CODE
mov ax, 1
mov bx, 5
add ax, bx
push ax
...
INTERFACE DO TURBO ASSEMBLER COM O TURBO PASCAL
O Turbo Pascal permite o acesso à quase totalidade dos recursos da máquina
através dos arrays Port[], Mem[], MemW[], MemL[] e permite usar a BIOS e
o sistema operativo com os procedimentos Intr() e MsDos().
As razões mais prováveis para se utilizar linguagem assembly no Turbo Pascal
são: executar as poucas operações que não estão directamente disponíveis a
partir do Turbo Pascal e tirar vantagem da velocidade que só a linguagem
assembly pode fornecer.
O Turbo Pascal impõe algumas restrições a nível de utilização de registos.
Quando é feita uma chamada a uma função ou procedimento, os valores dor
registos SS, DS e BP devem ser preservados. O DS aponta para o segmento de
dados global (DATA), o SS aponta para o segmento de pilha. O BP é usado
por cada rotina para referenciar o espaço que usa na pilha para parâmetros e
variáveis locais. Todas as rotinas devem também ajustar o SP antes de
terminar.
Para que uma subrotina seja do tipo far utiliza-se a directiva de compilador
{$F}.
A directiva {$L MYFILE.OBJ} faz com que o Turbo Pascal procure o ficheiro
MYFILE.OBJ e a linque com o programa em Turbo Pascal.
25
Arquitectura de Computadores / ESTG-IPL
Cada rotina em Turbo Assembler que se deseje tornar visível no programa
Turbo Pascal deve ser declarada como um símbolo PUBLIC e ter uma
declaração external correspondente no programa.
Se um programa em Turbo Pascal declarar as seguintes variáveis globais:
var
a: byte;
b: integer;
c: real;
d: pointer;
Podem aceder-se estas variáveis dentro do programa em assembly com as
declarações EXTRN:
EXTRN a: byte
; 1 byte
EXTRN b: word
; 2 bytes
EXTRN c: fword ; 6 bytes
EXTRN d: dword ; 4 bytes
Convenções de passagem de parâmetros do Turbo de Pascal
O Turbo Pascal passa parâmetros através da pilha.
Parâmetros de 1 byte são passados como uma palavra de 16 bits sendo o byte
mais significativo ignorado.
Em parâmetros de 4 bytes, é colocada primeiro na pilha a palavra mais
significativa.
Em parâmetros do tipo ponteiro, é colocada primeiro na pilha a palavra que
contém o segmento, depois a do deslocamento. No programa em Turbo
Assembler pode usar-se as instruções LDS ou LES para se ter acesso a um
parâmetro do tipo ponteiro.
Parâmetros do tipo string, não são colocados na pilha. Em vez disso o Turbo
Pascal coloca na pilha um ponteiro far para a string.
Os parâmetros variáveis (var) são passados como um ponteiro para a sua
localização na memória.
Quando as rotinas do Turbo Assembler recebem controlo, o topo da pilha
contém um endereço de retorno (uma ou duas palavras) e, acima dele,
quaisquer parâmetros a serem passados. Uma forma de aceder os parâmetros
passados para a rotina em Turbo Assembler é usar o registo BP para endereçar
a pilha.
A directiva .MODEL com o parâmetro TPASCAL fornece suporte
simplificado de segmentação, modelo de memória e de linguagem. Esta
directiva encarrega-se da salvaguarda e restauro do registo BP, de lhe atribuir
o valor de SP e de fazer a gestão do espaço ocupado pelos parâmetros na
pilha.
As funções no Turbo Pascal devolvem os seus valores em registos ou na pilha.
Valores de 1 byte são devolvidos no registo al, 2 bytes no ax, 4 bytes em
dx:ax.
26
Arquitectura de Computadores / ESTG-IPL
MICROPROCESSADORES x86 MAIS EVOLUÍDOS
O Turbo Asembler pode suportar, além do processador 8086, vários outros
tipos de procesadores, através de directivas como: .186, .286, .386, etc.
As principais características que cada um destes processadores veio
acrescentar foram novas instruções e novos modos de endereçamento.
O 386 fornece, entre outras inovações:
- novas instruções e extensões a instruções existentes,
- um conjunto extendido de registos de 32 bits e segmentos lineares de até 4
GB (32 bits) e
- instruções privilegiadas (.386P) destinadas apenas a serem usadas pelo
sistema operativo.
O 386 extende os registos gerais, o registo de flags e o ponteiro de instrução
para 32 bits e adiciona dois novos registos de segmento: fs e gs.
Surgem novos modos de endereçamento: os 8 registos de 32 bits de uso geral
(eax, ebx, ecx, edx, esi, edi, ebp e esp) podem ser utilizados como registos
base ou índice.
Não existe acesso directo aos 16 bits mais significativsos dos registos de 32
bits. Para se usarem os 16 bits mais significativsos de eax, é necessário rodar o
registo 16 bits, aceder os 16 bits (agora) menos significativos e rodar
novamente 16 bits. Para, por ex., colocar ax na palavra mais significativa de
edx:
ror edx, 16
mov dx, ax
ror edx, 16
Figura - Os registos do 80386
27
Download