Um interrupt, pelo menos ao nível do Z80, é basicamente a recepção de um sinal externo em que a CPU, recebendo e aceitando, interrompe o que está fazer, guarda o endereço de execução no stack, e salta para uma "subrotina".
O processador Z80 tem dois tipos de interrupts: não mascaráveis (NMI) e mascaráveis.
As NMI (Non-Maskable Interrupts) são interrupts que não podem ser ignoradas, e chamam a subrotina em $0066; a NMI não funciona sem hardware adicional, devido a um bug na ROM. São activadas com o pino NMI do Z80.
RESET
|
0066
|
PUSH AF
|
Save the current values held in these registers.
|
|
0067
|
PUSH HL
|
|||
0068
|
LD HL,($5CB0)
|
The two bytes of NMIADD must both be zero for the reset to occur.
|
||
006B
|
LD A,H
|
|||
006C
|
OR L
|
|||
006D
|
JR NZ,$0070
|
Note: this should have been 'JR Z'!
|
||
006F
|
JP (HL)
|
Jump to START.
|
||
NO_RESET
|
0070
|
POP HL
|
Restore the current values to these registers and return.
|
|
0071
|
POP AF
|
|||
0072
|
RETN
|
A interrupção não-mascarável BUSRQ não tem utilidade na arquitectura do ZX Spectrum e raramente é mencionada.
As mascaráveis são activadas 50 vezes por segundo, com a ULA a enviar um sinal ao pino INTR do Z80. Note-se que o envio deste sinal coincide no ZX Spectrum 48K com o inicio do varrimento do ecrã pela ULA.
As interrupções mascaráveis podem ser ignoradas pelo software fazendo DI anteriormente e EI de novo para as aceitar. Têm três modos de funcionamento no Z80:
- IM0
- IM1
- IM2
Em IM0 e IM1, chegando um interrupt, é equivalente a um RST $38. Isto executa a rotina da ROM em $0038, MASK_INT, que incrementa variáveis de contar tempo (FRAMES), e chama a rotina da ROM de varrimento de teclado.
MASK_INT
|
0038
|
PUSH AF
|
Save the current values held in these registers.
|
|
0039
|
PUSH HL
|
|||
003A
|
LD HL,($5C78)
|
The lower two bytes of the frame counter (FRAMES) are incremented every 20 ms. (U.K.) The highest byte of the frame counter is only incremented when the value of the lower two bytes is zero.
|
||
003D
|
INC HL
|
|||
003E
|
LD ($5C78),HL
|
|||
0041
|
LD A,H
|
|||
0042
|
OR L
|
|||
0043
|
JR NZ,KEY_INT
|
|||
0045
|
INC (IY+$40)
|
|||
KEY_INT
|
0048
|
PUSH BC
|
Save the current values held in these registers.
|
|
0049
|
PUSH DE
|
|||
004A
|
CALL KEYBOARD
|
Now scan the keyboard.
|
||
004D
|
POP DE
|
Restore the values.
|
||
004E
|
POP BC
|
|||
004F
|
POP HL
|
|||
0050
|
POP AF
|
|||
0051
|
EI
|
The maskable interrupt is enabled before returning.
|
||
0052
|
RET
|
Também podemos activar o modo IM2 por software. Neste modo, o registo I tem de ser previamente carregado com um valor. Como por defeito, o bus de Spectrum em modo descanso sem nenhum hardware tem o valor $FF, sendo activado uma interrupt, o endereço da rotina de tratamento desta interrupt vai ser obtido de dois bytes (uma word), em RAM apontada por I no byte alto e $FF no byte baixo.
por exemplo:
LD A,$F9
LD A,I
IM 2
RET
tendo em $F9FF o valor $F800, a rotina de interrupts em modo dois vai estar em $F800.
ORG $F800
:---- rotina pretendida
JP $0038
Tópicos "avançados"
Internamente ao Z80 existem dois flip-flops que guardam e são afectados pelos estados dos interrupts. São conhecidos por IFF1 (interrupt switch) e IFF2 (copy). A tabela de estados deles é esta:
O registo IY deve estar no valor original se se invocar rotinas da ROM (a ROM espera ter o IY com o valor $5C3A).
O Z80 toma cuidados para não acontecer um interrupt imediatamente a seguir a um DI (se for NMI), ou imediatamente a seguir a um EI. A única excepção a esta regra de poder acontecer um interrupt na instrução imediata a EI, é ter uma instrução HLT, que espera por um interrupt.
Um evento de recepção de interrupts, desliga as interrupts e incrementa o registo R.
Veja Interrupt Behaviour of the Z80 CPU para mais detalhes.
Nota adicional: o Z80 também tem um pino de sinal WAIT, que estende o corrente ciclo de bus para alem de 1 ciclo T. É destinado a ser usado por periféricos. No caso do desenho da ULA do Spectrum, preferiram optar por não o usar para controlar o Z80.
Sem comentários:
Enviar um comentário