Instrucoes de controlo
São seis as instruções que permitem controlar o
microprocessador Z80. A instrução NOP tem o código 0000 0000(2) e em nada
afecta o processamento da CPU. A instrução HALT suspende a operação da CPU
até que um interrupt seja recebido. Tem o código 0111 0110(2) <=> 76
(16). As instruções DI e EI inibem e permitem, respectivamente, a realização
de interrupções.
0 microprocessador Z80 tem disponível para o
utilizador três modos de interrupção. Se o modo seleccionado for o 0, o
dispositivo que gerou o sinal de interrupt tem a possibilidade de inserir no bus
de dados o código de uma instrução que é executada pela CPU. 0 modo 1 é um
modo simplificado em que a CPU, automaticamente, executa um «RESTART» (RST)
para a posição 0038H (RST 56), não sendo necessário qualquer hardware
exterior adicional (o antigo valor do PC é colocado na pilha).
As interrupções no modo 2 são as mais importantes
e poderosas que fazem parte da CPU Z80. Este modo permite uma chamada indirecta
para qualquer posição de memória. Neste modo, a CPU reconhece um endereço de
16 bits em que os oito bits de maior ordem estão armazenados no registo 1
(registo de interrupção, não confundir com os registos de índice) e os oito
bits de menor ordem são fornecidos pelo dispositivo gerador da interrupção.
Este endereço aponta para dois bytes, colocados sequencialmente numa tabela,
onde se situa o endereço da rotina de serviço à interrupção (fig. 31). A
CPU obtém automaticamente o endereço de começo da rotina e executa um salto (CALL)
para este endereço.
Existe um outro tipo de interrupt (NMI) que não pode
ser inibido pelo programador e que, portanto, será sempre aceite pelo
microprocessador.
Seguidamente vamos analisar em pormenor os mecanismos
de interrupção.
Resposta a Interrupções
A finalidade de um interrupt é permitir que um
dispositivo periférico interrompa, de uma forma ordenada, a operação da CPU
forçando-a a executar uma rotina de serviço ao periférico. Normalmente esta
rotina de serviço envolve a troca de dados, ou informação de controlo, entre
a CPU e o periférico. Uma vez completa a rotina de serviço, a CPU retoma a
execução do programa principal no ponto onde o processamento foi interrompido
pelo pedido de interrupção.
1 - Permissão e inibição de interrupts.
0 microprocessador Z80 possui dois pinos
correspondentes a duas entradas de interrupção podendo uma delas ser inibida
(mascarada) por programação (software maskable interrupt). Entende-se por máscara
o estado de inibição de uma interrupção. 0 interrupt não «mascarável»,
NMI (non maskable interrupt), não pode ser inibido
pelo programador, isto é, este interrupt será aceite pela CPU sempre que um
periférico o requeira. Geralmente, reserva-se este tipo de interrupção para
as funções mais importantes que devem ser executados logo que ocorram.
A interrupção que se pode «rriascarar,, (INT) pode
ser, selectivamente, permitida (enabie) ou proibida (disabie) pelo programador.
Este facto permite ao utilizador impedir os interrupts, durante os períodos em
que o programa está sujeito a limitações de tempo, libertando a CPIJ de possíveis
pedidos de interrupção.
0 microprocessador Z80 contém um flip-flop,
designado por I FF, que é colocado no estado «1» (set) sempre que sejam possíveis
interrupções e no estado «0» (reset) sempre que as interrupções não sejam
permitidas. A instrução EI (enable interrupt) coloca a «1 » o flip-flop IFF,
enquanto a instrução DI (disable interrupt) posiciona a «0» o mesmo
flip-flop. Então, quando IFF está no estado «0» um pedido de interrupção não
pode ser aceite pela CPU.
Na verdade, por razões que serão explicadas a
seguir, a CPU contém dois flip-flops destinados à permissão (enable) e proibição
(disable) das interrupções. Estes flip-flops são designados por IFF1 e IFF2:

A instrução EI coloca ambos os flip-flops no
estado de permissão de interrupções. Quando uma interrupção é aceite pela
CPU, IFF1 e IFF2 são colocados automaticamente a «0» inibindo outros pedidos
de interrupção. Com a execução de uma nova instrução EI o estado dos
flip-flops passa da inibição para a permissão. Note-se que até este momento
os estados de IM e IFF2 são sempre iguais.
Um reset da CPU força tanto IFF1 como IFF2 a
conterem o valor «0» sendo proibidas as interrupções. Para as permitir de
novo, o programador pode introduzir, em qualquer momento, uma instrução EI.
Quando uma instrução EI é executada, qualquer pedido de interrupção que
esteja pendente não será aceite antes de a instrução que se segue a EI também
ter sido executada. Este atraso introduzido é necessário para os casos em que
a instrução seguinte representa uma operação (RETURN). Neste caso, as
interrupções não devem ser aceites sem antes ter sido executada a instrução
de retorno. Na figura 30 ilustra-se esta situação, em que um pedido de
interrupt é gerado durante a execução de uma sub-rotina.

0 propósito do flip-flop IFF2 é ressalvar o
estado de IFF1 quando ocorre um interrupt não «mascarável» (NMI). Quando um
interrupt NMI é aceite, o flip-flop IFF1 é colocado no estado «0» para
inibir outros pedidos de interrupção que possam surgir. Assim, depois de um
interrupt NMI ter sido aceite as interrupções «mascaráveis» são proibidas
mas o estado primitivo de IFF1 é salvaguardado (IFF2), pelo que o estado da CPU,
anterior à interrupção NMI, pode ser restaurado em qualquer momento.
Quando a instrução LD A, I (ou LD A, R) é
executada, o estado do flip-flop IFF2 é copiado para a flag de paridade. Então,
o conteúdo da flag pode ser testado e uma opção pode ser tomada quanto à
execução de uma instrução EI (executanto-se EI se o valor de P/V for «1»).
Um segundo método para restaurar o estado de IFF1 é
através da execução da instrução de retorno de um interrupt NMI (instrução
RETN). Uma vez que esta instrução indica que a rotina de serviço a uma
interrupção NMI terminou, o conteúdo de IFF2 é copiado para IFF1,
restaurando-se automaticamente o estado deste flip-flop com o valor que continha
anteriormente à aceitação do interrupt.
Resumindo, o efeito nos dois flip-flops das
diferentes instruções é o seguinte:

● o indica que não há alteração
2 - Reposta da CPU
a) Interrupções não «mascaráveis» (NMI)
Uma interrupção não «mascarável», será
aceite depois de terminada a operação que está a ser executada pela CPU.
Quando ocorre, a CPU ignora a próxima instrução a executar e efectua um
restart para a posição 0066H. Tudo se passa como se a CPU executasse uma
instrução RST. A diferença reside unicamente no facto de nenhuma das oito
posições da instrução RST servir de endereço de salto (o salto é para a
posição 66H). Um restart é simplesmente uma chamada (ca11) para uma posição
na página 0 da memória (0000 - OFFF). 0 flip-flop 1 inibe as interrupções
INT (IFF1 a 0). 0 retorno da sub-rotina de interrupção que serve o NMI é
feito com a instrução RETN porque esta instrução repõe o flip-flop 1 no
estado em que se encontrava antes da interrupção NMI. Durante a sub-rotina de
interrupção NMI não são aceites interrupções INT porque IFF11 =0. 0
flip-flop 2 IFF2 memoriza temporariamente o estado do flip-flop durante a
sub-rotina de interrupção NMI.
b) Interrupções «mascaráveis» (INT)
A CPU pode ser programada de três modos
diferentes para responder a este tipo de interrupções.
Modo 0
Neste modo o dispositivo gerador do sinal de
interrupção tem a possibilidade de colocar o código de qualquer instrução
no barramento de dados, para depois a CPU a executar. Assim, é o dispositivo
que interrompe o processamento do programa que fornece a próxima instrução a
ser executada, em vez de esta ser extraída da memória como normalmente sucede.
Frequentemente esta instrução representa um restart (RSI), uma vez que o
dispositivo exterior só necessita de fornecer um código formado por um único
byte.
Alternativamente, qualquer outra instrução,
tal como um CALL formado por três bytes, pode ser executada, pois a CPU gera os
sinais necessários de modo a prolongar o cicio de resposta ao interrupt e obter
tempo suficiente para a recepção dos três bytes da instrução.
Depois da aplicação de RESET a CPU fica de imediato
no modo 0.
Modo 1
Quando este modo é seleccionado pelo
utilizador a CPU responde a um interrupt executando um restart para a posição
0038 H da memória (RST 56). Assim, esta resposta é idêntica à de um
interrupt NMI, com a diferença de que a posição para onde salta o
processamento é a 38 H em lugar de 66 H.
Modo 2
Como já foi referido anteriormente, o modo 2
é o mais importante e poderoso. Através de oito bits (um byte) fornecidos pelo
utilizador, uma chamada indirecta pode ser executada para qualquer posição de
memória.
Neste modo o programador constrói uma tabela de
endereços, de 16 bits, representando cada um deles o início de uma rotina de
serviço. Esta tabela pode estar localizada em qualquer local da memória.
Quando uma interrupção é aceite, é formado um
ponteiro de 16 bits que aponta a posição de memória onde se encontra o endereço
da sub-rotina de serviço a essa interrupção, isto é, uma posição de tabela
de endereços é seleccionada.
Os oito bits mais significativos deste ponteiro são
constituídos pelo conteúdo do registo 1. Este registo teve de ser carregado
previamente pelo utilizador com o valor desejado, ou seja, a CPU executa
anteriormente a instrução LD I, A. De notar que um reset da CPU coloca a zero
o conteúdo do registo 1, pelo que este registo é inicializado com zeros.
Os oito bits menos significativos do ponteiro são
fornecidos pelo dispositivo que requereu a interrupção. Na verdade, só sete
bits são obtidos do dispositivo que gerou o sinal de interrupt, pois o bit
menos significativo deve ser sempre «0». Este facto verifica-se porque o
ponteiro é utilizado na obtenção de dois bytes adjacentes, de modo a
formar-se o endereço de 16 bits do início da rotina de serviço, devendo o
primeiro destes bytes situar-se numa posição par (fig. 31).

0 primeiro byte da tabela representa o byte
menos significativo do endereço da sub-rotina. Obviamente o programador deve
preencher a tabela com os endereços desejados antes de qualquer interrupção
ser aceite.
De notar que esta tabela pode ser modificada em
qualquer momento pelo utilizador (desde que se encontre numa zona de memória
RAM), permitindo que periféricos diferentes sejam servidos por sub-rotinas
diferentes.
Em qualquer dos modos de interrupção apresentados o
conteúdo inicial do contador de programa é sempre guardado na pilha, para ser
reposto no final da sub-rotina de serviço ao interrupt (instrução de
retorno). Convém salientar também que um interrupt gerado durante a execução
de uma instrução só será atendido depois de essa instrução ter sido
completamente executada.
Na figura 32 está ilustrado o processo de execução
de um pedido de interrupção no modo 2. A tabela de endereços de sub-rotinas
de serviço começa na posição OAOO H. 0 endereço da sub-rotina que o periférico
pretende que a CPU execute encontra-se nas posições 0A10 H e 0A11 H. Então, o
registo 1 deve conter o valor OA H e o dispositivo gerador da interrupção deve
colocar no barramento de dados o vector 10 H (vector interrupt). Deste modo, é
obtido o endereço 1800 H para início da sub-rotina de serviço.

0 microprocessador Z80 permite a execução de vários
níveis de interrupts (fig. 33), isto é, durante a execução de uma sub-rotina
de serviço a uma interrupção podem surgir e ser aceites outros pedidos de
interrupção desde que seja executada a instrução EI dentro destas
sub-rotinas. Cada uma destas sub-rotinas termina por uma instrução de retorno
que conduz sistematicamente o processamento para a sub-rotina mais exterior
(primeiro pedido de interrupção), atingindo-se por fim o programa principal.
Note-se que o nível das sub-rotinas está condicionado pela existência da
instrução EI em cada uma das sub-rotinas, visto que quando o sinal de interrupção
é aceite a CPU automaticamente proíbe novas interrupções.

As instruções EI e DI são formadas por um único
byte e, tal como tem sido referido repetidas vezes, desinibem e inibem,
respectivamente, a ocorrência de interrupções:

As instruções SET INTERRUPT MODE seleccionam
um dos três modos de utilização da entrada de interrupt que se pode mascarar.
São instruções de dois bytes com o seguinte formato:

Por último, resta-nos apresentar os códigos
das instruções de RETURN das sub-rotinas de serviço de interrupções (RETN e
RETI):

A instrução RETN é utilizada no fim das
sub-rotinas de resposta a um interrupt NMl (que não pode ser inibido). Esta
interrupção carrega o flip-flop IFF1 com o valor de IFF2, como foi referido
anteriormente.
A instrução RETI é utilizada para terminar as
sub-rotinas de resposta às interrupções que se podem mascarar (INT).
Na tabela 29 apresenta-se um resumo dos códigos
hexadecimais das instruções de controlo da CPU.
