Você está na página 1de 10

MC-LAB - LABORATÓRIO 04: USANDO A PILHA E SUBROTINAS

1. Objetivos

Após completar estas atividades você deverá ser capaz de:


? Entender a necessidade e o uso da pilha;
? Executar sub-rotinas;
? Entender e usar as seguintes instruções do 8085: CALL, RET, ADI, JC, PUSH e POP.

2. Equipamento necessário

? Unidade microcomputador MC-1


? Fonte de alimentação de 5 volts MB-2F

3. Teoria

ANTES DE INICIAR A PARTE PRÁTICA, LEIA ATENTAMENTE A TEORIA EXPOSTA NESTE ITEM E
NOS CAPÍTULOS 9 E 10 DO GAONKAR

A PILHA
A pilha é uma região da memória RAM reservada para armazenar, principalmente, endereços de retorno de
sub-rotinas. Pode também ser usada para armazenar o conteúdo de registradores, a fim de evitar que
sejam alterados ou destruídos por uma sub-rotina. As operações de pilha transferem dados de 16 bits entre
pares de registradores e a memória RAM. As duas operações básicas são o PUSH, que adiciona dados a
pilha, e o POP, que retira dados da pilha.
Por exemplo, os dados armazenados no registrador B de um programa serão perdidos se esse registrador
for usado durante uma sub-rotina. Uma instrução PUSH, executada no começo de uma sub-rotina, salvará
o conteúdo deste registrador. A instrução PUSH B armazena o conteúdo do par de registradores BC na
pilha. PUSH D armazena o conteúdo do par DE, PUSH H armazena o par HL e PUSH PSW armazena o
acumulador e o registrador F. PSW representa a palavra de estado do processador.
Ao final da sub-rotina, os dados são restaurados (devolvidos) aos registradores originais por uma instrução
POP. Uma instrução POP copia os dados armazenados na pilha para o par de registradores indicados na
própria instrução. Por exemplo, POP B restaura dados da pilha para os registradores B e C. Note que os
dados devem ser retirados da pilha na ordem inversa daquela em que foram inseridos. Portanto, a pilha é
uma estrutura de dados do tipo LIFO (Last In, First Out), ou seja, o último a entrar é o primeiro a sair. A
seqüência de instruções a seguir guarda e restaura todos os registradores:

PUSH PSW
PUSH B
PUSH D
PUSH H
.
Instruções da sub-rotina
.
POP H
POP D
POP B
POP PSW
RET

Para o controle da pilha, existe um registrador mantido pelo processador chamado ponteiro de pilha (SP)
Seu programa deverá iniciar este ponteiro. Isto significa que seu programa deverá carregar o endereço
base da pilha no SP. Este endereço base é normalmente o endereço mais alto da RAM. Isto porque a pilha
cresce a medida que o SP é decrementado, isto é, cresce do maior endereço para o menor. À medida que
se acrescentam itens à pilha, esta se expande para posições de memória com endereços mais baixos. A

24
única limitação ao número de itens que podem ser adicionados à pilha é a quantidade de RAM disponível
para a pilha.
Por exemplo, sempre que uma instrução PUSH B é executada, o SP é decrementado de uma unidade, o
conteúdo do registrador B é copiado para a posição de memória apontada pelo SP. A seguir o SP é
decrementado novamente de uma unidade e o conteúdo do registrador C é copiado para a posição de
memória apontada por ele.
A instrução POP B copia o byte de dados anteriormente guardado na pilha de volta para o registrador C,
incrementa o SP, copia o próximo byte de dados guardado na pilha para o registrador B e incrementa
novamente o SP.
Após uma seqüência de PUSHs e POPs, o SP fica apontando para o mesmo endereço que ele continha
antes das operações.
SUB-ROTINAS
Uma rotina é uma pequena secção de programa que executa uma tarefa específica. Se for preciso usar um
procedimento muitas vezes num programa, pode-se gravá-lo uma única vez na memória na forma de uma
sub-rotina e então chamá-lo toda vez que for necessária. Este método ocupa bem menos memória que o
processo de rescrever o procedimento inteiro toda vez que o mesmo for utilizado.
Nenhum dos programas de laboratório que você usou até agora é um programa por si mesmo. A maior
parte dos programas reais executam uma série de tarefas, muitas das quais podem ser comuns a vários
outros programas. Você precisa de uma maneira de formular essas tarefas de uma só vez e torná-la
disponível tanto para diferentes partes de um programa quanto para outros programas.
Isto é possível escrevendo a tarefa como uma sub-rotina, cujas instruções resultantes possam ser gravadas
de uma só vez, testadas e a partir de então usadas repetidamente. Esta sub-rotina poderá tornar-se parte
de uma biblioteca de sub-rotinas, que fornecerá soluções para problemas comuns.
O 8085 tem instruções especificas para transferir o controle para sub-rotinas e devolver o controle ao
programa principal. A instrução CALL transfere o controle à sub-rotina e a instrução RET (return) devolve o
controle ao programa principal. A instrução CALL guarda o valor antigo do contador do programa na pilha
antes de colocar o endereço inicial da sub-rotina no contador de programa (PC).
A instrução RET recupera o valor antigo da pilha e o coloca de volta no contador de programa. O efeito é a
transferência do controle do programa, primeiro para a sub-rotina e depois de volta ao programa principal.
Uma sub-rotina também pode transferir o controle para outra sub-rotina e assim por diante. Esse processo
é chamado aninhamento; isto significa que uma instrução CALL numa sub-rotina pode chamar outra sub-
rotina.

4. Experimentos

4.1. Uso da pilha

O Programa 1 mostra como usar a pilha. Este programa carrega pares de registradores com dados e
transfere estes dados para a pilha. Em seguida o programa recupera os dados da pilha.
ENDEREÇO DADOS ASSEMBLY COMENTÁRIOS
LXI SP,20A0 Inicializa o SP

LXI H,1234 Carrega o par HL

LXI D,5678 Carrega o par DE

LXI B,ABCD Carrega o par BC

XRA A Zera acumulador e ajusta flags


PUSH H Transfere HL para a pilha

25
PUSH D Transfere DE para a pilha
PUSH B Transfere BC para a pilha
PUSH PSW Transfere A e F para a pilha
RST 1 Ponto de Parada
STOP: POP PSW Recupera A e F
POP B Recupera BC
POP D Recupera DE
POP H Recupera HL
RST 1 Volta ao Monitor
Programa 1 - Uso da Pilha
Execute o Programa 1. Ele irá parar na posição de memória STOP (a instrução POP PSW não será
executada). Examine as posições de memória (relativas à pilha) e os registradores da CPU para os dados
da Tabela 1.
REGISTRADOR CONTEÚDO
A
F
B
C
D
E
H
L
PC
SP

ENDEREÇO CONTEÚDO
209F
209E
209D
209C
209B
209A
2099
2098
Tabela 1 - Resultados Parciais do Programa
Altere o conteúdo dos registradores A, B, C, D, E, H, L e F para FFH. Continue a execução do restante do
programa pressionando as teclas EXECUTE, GO e EXECUTE.
Verifique que ao final do programa os dados dos registradores são os originais! Complete a Tabela 2.
REGISTRADOR CONTEÚDO
A
F
B
C
D
E
H
L
PC
SP
Tabela 2 - Resultados do Programa

4.2. Gerando e verificando paridade

Um modo de reduzir o número de erros numa transmissão de dados é acrescentar-lhes informações para
detecção e correção de erros.

26
A paridade é um modo bastante simples para a detecção de erros. Ela consiste da adição de um único bit à
cada palavra, o qual torna o número total de bits "1" par (paridade par) ou ímpar (paridade ímpar).
Você pode facilmente gerar e verificar paridade com o microprocessador 8085, uma vez que ele possui um
flag de paridade par, que é colocado em 1 se a última operação lógica ou aritmética realizada pela ALU
produzir um resultado com paridade par.
O Programa 2 obtém o conteúdo da posição de memória 2050, coloca uma paridade ímpar no bit mais
significativo (assumido como zero originalmente), e armazena o resultado na posição de memória 2051.
A instrução ANI 7F realiza um AND lógico entre o conteúdo do registrador A e o valor 7FH. Ela seta os
flags de acordo com o conteúdo de A e limpa o flag de carry alterando somente o bit mais significativo de
A.
A instrução JPO (jump on parity odd) produz um desvio para o endereço especificado nos próximos dois
bytes da memória de programa se o flag de paridade for 0 (paridade ímpar); caso contrário continua na
próxima instrução da seqüência.
A instrução ORI 80 seta o bit mais significativo do acumulador.
END. DADOS ASSEMBLY COMENTÁRIOS
LXI SP,20A0 Inicializa o SP

LDA 2050 Carrega o número de dois dígitos no Acumulador.

ANI 7F Verifica se a paridade dos bits b0 a b6 já é ímpar. Zera


b7.

JPO NEXT Desvio para NEXT se a paridade é ímpar.

ORI 80 Caso contrário seta paridade ímpar.

NEXT: STA 2051 Armazena dado com paridade ímpar

RST 1 Volta ao Monitor


Programa 2 - Gerando paridade
Execute o Programa 2 de acordo com o seguinte procedimento:
a) Entre com o programa a partir do endereço 2000.
b) Entre um número no endereço 2050 que contenha um número ímpar de bits em 1, por exemplo 23H.
c) Examine o conteúdo das posições de memória de 2000H até 200F e 2050, para ter certeza que você
entrou com o programa e com o dado corretamente.
d) Execute o programa no modo single-step.
e) Execute a instrução ANI e observe o bit de paridade do registrador de flags F = _______.
f) Execute este programa colocando um byte no endereço 2050 que contenha um número par de bits
em 1, como, por exemplo, 22H.
g) Execute a instrução ANI e observe o bit de paridade do registrador de flags F = _______.
h) Execute o programa no modo contínuo.

4.3. Escrevendo uma subrotina

O Programa 3 usa a subrotina PARITY para gerar um bit de paridade. O programa principal busca os
conteúdos das posições de memória 2050 e 2051, chama a subrotina PARITY para gerar o bit de paridade
e armazena os resultados na posição 2060 e 2061.
Vamos observar as instruções:

27
1. LXI SP, 20A0 carrega o stack pointer com a palavra 20A0.
2. LXI H,2050 define o ponteiro de endereços.
3. CALL PARITY chama a subrotina PARITY e salva o valor antigo do Program Counter.
A subrotina funciona do seguinte modo:
1. PUSH H e PUSH PSW armazenam o par de registradores HL e a PSW (Processor Word Status) na
pilha.
2. ANI 7F, seta o flag de paridade de acordo com o conteúdo da posição de memória 2050H (ou 2051
na segunda vez).
3. JPO e ORI 80H colocam a paridade ímpar no bit mais significativo do acumulador, que é assumido
como zero inicialmente.
4. LXI D,0010 e DAD D adicionam o número hexadecimal 10 ao conteúdo do par de registradores HL,
setando o ponteiro de endereços para a posição 2060 (ou 2061 na segunda vez).
5. MOV M,A armazena o resultado na posição de memória 2060 (ou 2061 na segunda vez).
6. POP PSW e POP H carregam a PSW e o par de registradores HL a partir da pilha.
7. RET indica um retorno para o programa principal.

END. DADOS ASSEMBLY COMENTÁRIOS


LXI SP,20A0 Inicializa o SP

LXI H,2050 Inicializa HL

XRA A Inicializa o PSW


CALL PARITY Chama a subrotina PARITY

INX H Incrementa o ponteiro de endereços


CALL PARITY Chama a subrotina PARITY

RST 1

SUBROTINA PARITY

PARITY: PUSH H Salva o par de registradores HL


PUSH PSW Salva o registrador A e os flags
MOV A,M Carrega o número no Acumulador
ANI 7F Verifica se a paridade dos bits b0 a b6 já é ímpar. Zera b7.

JPO NEXT Desvio para NEXT se a paridade é ímpar.

ORI 80 Caso contrário seta paridade ímpar.

NEXT: LXI D,0010 Define o offset do endereço

DAD D Adiciona offset ao ponteiro


MOV M,A Armazena dados com o bit de paridade
POP PSW Recupera o registrador A e os flags
POP H Recupera o par de registradores HL
RET Volta ao programa principal
Programa 3 - Escrevendo uma subrotina

28
Execute o Programa 3 de acordo com o seguinte procedimento:
a) Entre com o programa a partir do endereço 2000.
b) Entre com a rotina PARITY a partir do endereço 2010.
c) Entre o valor “00”no endereço 2050 e “01”no endereço 2051.
d) Examine o conteúdo das posições de memória de 2000H até 2020, 2050 e 2051, para ter certeza que
você entrou com o programa e com o dado corretamente.
e) Execute o programa no modo single-step.
f) Execute a instrução CALL PARITY.
g) Note que o Program Counter estará apontando para a primeira instrução da subrotina
h) Execute as instruções PUSH H e PUSH PSW (da subrotina).
i) Verifique o conteúdo das seguintes posições de memória (pilha):

ENDEREÇO CONTEÚDO
209F
209E
209D
209C
209B
209A
Tabela 3 - Pilha
j) Note que os quatro últimos bytes armazenados nestas posições estão de acordo como os quatro
bytes dos registradores H, L, A e F.
k) Execute as instruções MOV A,M e ANI 7F. Observe o conteúdo dos registradores e anote na Tabela
4.
REGISTRADOR CONTEÚDO
A
F
B
C
D
E
H
L
PC
SP
Tabela 4 - Conteúdo dos registradores

l) Repita os itens f até k para a segunda chamada da subrotina PARITY.

ENDEREÇO CONTEÚDO
209F
209E
209D
209C
209B
209A
Tabela 5 - Pilha

29
REGISTRADOR CONTEÚDO
A
F
B
C
D
E
H
L
PC
SP
Tabela 6 - Conteúdo dos registradores

m) Justifique o conteúdo da pilha

4.4. Conversão hexadecimal para ASCII

O Programa converte um número HEX do tipo 0X, com X = 0, ..., F, num caracter ASCII. O Programa esta
mostrado na listagem abaixo; a Figura 1 apresenta o seu fluxograma.
O programa principal deve ser escrito a partir do endereço 2000.
A sub-rotina de conversão deve ser escrita a partir do endereço 2020.
ENDEREÇO DADOS ASSEMBLY COMENTÁRIOS
LXI SP,20A0 Inicializa o SP

LDA 2040 Obtém o número Hexadecimal

CALL ROT Chama a sub-rotina de conversão

STA 2041 Armazena o resultado

RST 1 Fim do programa principal

ROT: CPI 0A Início sub-rotina. Verifica se (A) > 09

JC L1: Se (A) = 09, salte para L1

ADI 07 Se (A) > 09, adicione offset da letra.

L1: ADI 30 Se (A) = 09 adiciona offset ASCII

RET Retorna ao Programa Principal


Programa 4 - Conversão HEX para ASCII

30
INÍCIO

(A) > 9 ? No

Yes

(A) = (A) + 07

(A) = (A) + 30

FIM
?
Figura 1 - Fluxograma do Programa 4?
Execute o Programa 4 para os dados da Tabela 5. Complete esta tabela escrevendo o código ASCII obtido
(resultado do endereço 2041) e o símbolo ASCII correspondente.

ENDEREÇO 2040 ENDEREÇO 2041 SÍMBOLO ASCII


0C
06
01
0D
0F
Tabela 5 - Resultados do programa

4.5. Conversão BCD para binário

O propósito deste experimento é carregar e executar um programa conversor de BCD para binário. O
Programa 5 inicia transferindo o número BCD de 2 dígitos para o acumulador. O número é separado em
dois dígitos de 4 bits cada um. O primeiro dígito de 4 bits é mascarado pela instrução ANI 0F, que significa
“Realize a operação lógica AND entre o byte imediato (0F) e o conteúdo do acumulador". Note que o
número hexadecimal 0F é equivalente ao número binário 0000 1111.
O segundo dígito de 4 bits é mascarado pela instrução ANI F0, onde F0 é equivalente ao número binário
1111 0000.
O dígito BCD mais significativo é deslocado duas vezes para a direita através do flag de carry. Isto é
realizado pela execução das instruções RRC. O resultado parcial é armazenado no registrador C. A seguir,
o dígito BCD mais significativo é deslocado novamente para a direita através do flag de carry, adicionado
ao registrador C e deslocado para a esquerda através do carry.
Finalmente, este valor é adicionado ao dígito BCD menos significativo. Deste modo a conversão BCD para
binário é obtida.
O endereço 2050 contém o número BCD de dois dígitos, enquanto o endereço 2051 contém o resultado da
conversão.

ENDEREÇO DADOS ASSEMBLY COMENTÁRIOS


LXI SP,20A0 Inicializa o SP

LDA 2050 Carrega o número BCD de dois dígitos no Acc.

MOV C,A Move o conteúdo de A para C

31
ANI 0F Mascara o dígito BCD mais significativo

MOV E,A Move o conteúdo de A para E


MOV A,C Move o conteúdo de C para A.
ANI F0 Mascara o dígito BCD menos significativo

RRC Desloca o conteúdo de A um bit para a direita através


do flag de carry
RRC Desloca o conteúdo de A um bit para a direita através
do flag de carry
MOV C,A Move o conteúdo de A para C
RRC Desloca o conteúdo de A um bit para a direita através
do flag de carry
RRC Desloca o conteúdo de A um bit para a direita através
do flag de carry
ADD C Adiciona o conteúdo de C ao acumulador
RLC Desloca o conteúdo de A um bit para a esquerda
através do flag de carry
ADD E Adiciona o conteúdo de E ao acumulador
STA 2051 Armazena o resultado no endereço 2051

RST 1 Volta ao Monitor


Programa 5 - Conversão BCD para binário
Execute o Programa 5 de acordo com o seguinte procedimento:
a) Entre com o programa a partir do endereço 2000.
b) Entre um valor BCD de dois dígitos, por exemplo 33, no endereço 2050.
c) Examine o conteúdo das posições de memória de 2000H até 2018 e 2050, para ter certeza que você
entrou com o programa e com o dado corretamente.
d) Execute o programa no modo single-step.
e) Execute a primeira instrução ANI e observe que você obteve o seguinte resultado no acumulador:
A = 0011 0011 (correspondente ao número 33h)
Mask = 0000 1111 (correspondente à máscara 0Fh)
A and Mask = 0000 0011 (resultado)
f) Observe os diversos registradores e complete a Tabela 6.
REGISTRADOR CONTEÚDO
A
F
B
C
D
E
H
L
SP
PC
Tabela 6 - Conteúdo dos registradores
g) Execute o programa até a última instrução. O resultado estará contido no acumulador e na posição
de memória 2051. Para o número BCD 33 o resultado da conversão será 21H
h) Teste o programa para diferentes números BCD.
i) Execute o programa no modo contínuo.

32
5. Análise dos resultados

1. Descreva as seguintes instruções PUSH rp, POP rp.


2. O que é o código ASCII ? (Pesquise)
3. Qual é o código ASCII do caracter “a”?
4. Explique o algoritmo usado no Programa 4 para a conversão HEX para ASCII.
5. Explique o algoritmo usado no Programa 5 para a conversão BCD para binário.
6. Explique as Tabela 1. Relacione a tabela com os conteúdos dos endereços com a tabela com os
conteúdos dos registradores.

33