Taki artykuł się kiedyś pojawił w ZX LAND :p
Jest też na stronie Yarka:
http://yarek.com/forum/index.php?topic=64.0Tutaj kopia.
-----------------------------------------------------------------------------------------------------
Przerwania w trybie IM2Co to jest przerwanie (interrupt)? Jest to cykliczne (lub po spełnieniu określonych warunków) wywołanie podprogramu niezależnie od aktualnie wykonywanych operacji. Następnie po wykonaniu odpowiedniego podprogramu powrót do właściwej pracy bez naruszenia programu głównego.
ZX Spectrum posiada trzy tryby przerwań. IM0 - przerwania zarezerwowane dla podprogramów RST (0,8,16,24,32,40,48,56), IM1 - przerwania zarezerwowane dla podprogramów RST 56. Te tryby w zasadzie nas nie interesują.
IM2 - to przerwania dowolnego wykorzystania dla urządzeń zewnętrznych i programów umieszczonych w pamięci, którymi to właśnie się szerzej zajmiemy.
Na początek warto wiedzieć, że przerwanie występuje równo co 1/50 sekundy i zaczyna się w momencie rozpoczęcia wyświetlania zawartości ekranu (czyli początek tzw. ramki).
W momencie przerwania następuje zapamiętanie na stosie adresu instrukcji do wykonania, gdy już powrócimy z przerwania.
Starszy bajt adres skoku do obsługi przerwania wskazuje rejestr
I. Młodszy zależy od stanu szyny krawędziowej. Generalnie, gdy nic nie jest podpięte do szyny wartość ta powinna wynosić 255. Jeżeli do rejestru I zadamy wartość #BE, to w momencie przerwania zostanie pobrana z tablicy wektorów zaczynającej się od adresu #BE00 dwubajtowa liczba, która zawierać będzie adres pod który nastąpi skok. Tablica wektorów zawsze powinna zaczynać się od tzw. strony kodowej (#BF00, #C200) i zawierać
257 bajtów wypełnionych jednakową wartością. Jeżeli wypełnimy tablicę wartością #BF, to adresem, pod który nastąpi skok, zawsze będzie #BFBF. Tam też należy umieścić procedurę obsługi przerwania.
Ponieważ główny program zostaje przerwany w różnych momentach jego wykonywania, podprogram (wykonywany na przerwaniach) może zniszczyć jego aktualne rejestry. Po wyjściu z przerwania może nastąpić więc zawieszenie komputera lub nawet reset, gdyż wartości rejestrów mogły ulec zmianie. Aby temu zapobiec, warto w obsłudze przerwania zapamiętać aktualny stan rejestrów na stosie (komendy
PUSH nn, gdzie nn jest dowolną parą rejestrów np. HL, BC, AF...). Dopiero wtedy wykonujemy podprogram np. odgrywanie muzyki, scrolla, zegarek itp. Po wykonaniu podprogramów na przerwaniach należy odtworzyć zapamiętane rejestry (komendy
POP nn). UWAGA! Należy pamiętać o
odwrotnej kolejności zdejmowania ze stosu zawartości rejestrów w stosunku do ich zapamiętywania. Wyjście z przerwania następuje po instrukcji
RET (jak w zwykłym podprogramie), co powoduje zdjęcie ze stosu adresu instrukcji do wykonania zapamiętanej w momencie przerwania.
Należy jeszcze zadbać o możliwość włączania i wyłącznia przerwań w dowolnym momencie. Obie opcje znajdują się na końcu listingu.
; obsługa przerwań
ORG #BFBF
; zapamiętanie aktualnych wartości rejestrów
PUSH IY
PUSH IX
PUSH HL
PUSH DE
PUSH BC
PUSH AF
; wymiana rejestrów na alternatywne
EXX
EX AF,AF'
; zapamiętanie rejestrów alternatywnych
PUSH HL
PUSH DE
PUSH BC
PUSH AF
. . .
; miejsce na skoki do podprogramów - 16 bajtów
; max 5 x CALL
. . .
; przywrócenie wartości rejestrów alternatywnych sprzed przerwania
POP AF
POP BC
POP DE
POP HL
; wymiana rejestrów pomiędzy alternatywnymi i zwykłymi
EX AF,AF'
EXX
; przywrócenie wartości rejestrów
POP AF
POP BC
POP DE
POP HL
POP IX
POP IY
; wyjście z przerwania
EI
RET
; tworzenie tablicy wektorów dla przerwań
ORG #BFE9
INIT LD A,#BF
LD HL,#BE00
LD B,#00
LOOP LD (HL),A
INC HL
DJNZ LOOP
LD (HL),A
; włączenie przerwań IM 2
ORG #BFF5
ON LD A,#BE
LD I,A
IM 2
RET
; wyłączenie przerwań IM 2 - włączenie IM 1
ORG #BFFC
OFF EI
IM 1
RET
#BF = 191
#BE00 = 48640
#BFBF = 49087
#BFD9 = 49113
#BFE9 = 49129
#BFF5 = 49141
#BFFC = 49148
Od adresu #BF01 do #BFBE (pomiędzy końcem tablicy, a początkiem obsługi przerwań) pozostaje pusty obszar dokładnie 190 bajtów do wykorzystania. Można tam umieścić np. procedurkę wymazywania ekranu, obsługę klawiatury lub wykorzystać w dowolny inny sposób.
Chcąc stworzyć tablicę wektorów przerwań i włączyć przerwania wykonujemy USR (CALL) 49129, samo włączenie przerwań (gdy tablica już jest) USR (CALL) 49141 oraz USR (CALL) 49148 w przypadku wyłączenia przerwań.
Dlaczego na obsługę przerwań wybrałem akurat "środek" pamięci? Druga ćwiartka pamięci (adresy od 16384 do 32767) jest to tzw. pamięć wolna, tzn. odczyt z tych komórek jest normalny, natomiast zapis do nich jest spowalniany przez układ ULA, który dodatkowo śmieci ekran dziwnymi krzaczkami (zwanymi także flickersami lub artefaktami) jeżeli w rejestrze I jest wartość mniejsza niż 128 (#80). Czwarta ćwiartka natomiast (49152-65535) może być wykorzystywana przez podprogramy zmieniające banki pamięci (ZX128kB), więc gdy umieścimy obsługę w tamtym obszarze i zmienimy bank może to doprowadzić do zawieszenia lub restartu komputera.
Warto jeszcze wiedzieć, że zwykle programy wykonywane na przerwaniach posiadają tzw. inicjację i często skompilowane np. od adresu 40000 pierwsze 3 bajty zajmuje skok JP adres_inicjacji, w celu ustawienia wartości początkowych procedury. W przypadku scrolla może być to np. ustawienie początku tekstu, w muzyce - początek utworu, wyciszenie dźwięku itp. Np. w skompilowanej od adresu 40000 muzyce z Sound Tracker'a inicjacja znajduje się pod 40000 natomiast wywołanie odgrywania muzyki pod 40006, czyli 6 bajtów dalej.