MAPA PAMIĘCIW każdym komputerze prędzej, czy później spotykamy się z przerwaniami. Urządzenia firmy ATARI oczywiście nie są pod tym względem wyjątkiem. W nich także występuje cała gama przerwań, używanych do różnych celów przez system operacyjny oraz programy użytkowe. Przerwania, ogólnie rzecz biorąc, dzieli się na maskowalne (tzw. IRQ, z ang. Interrupt ReQuest), oraz niemaskowalne (NMI. z ang. Non-Maskable Interrupt). Podstawową różnicą pomiędzy nimi jest to, jak procesor może je potraktować. Przerwania maskowalne mogą zostać zignorowane przez jednostkę centralną dzięki rozkazowi SEI, a ten stan obojętności trwa dotąd, aż w programie pojawi się rozkaz CLI. Jak łatwo się domyślić, przerwania niemaskowalne nie mogą zostać przez procesor nie zauważone, chociaż w większości systemów istnieje możliwość zablokowania ich poprzez zapisanie odpowiednich rejestrów sprzętowych. Przerwanie VBLANK należy do grupy przerwań niemaskowalnych i jest najważniejszym spośród wszystkich przerwań, występujących w ATARI. Co oznacza nazwa VBLANK? Otóż oznacza ona przerwanie wygaszania pionowego, czyli zgłaszane wtedy, gdy strumień elektronów, 'rysujący' obraz na monitorze dociera do prawego dolnego rogu ekranu. Zasada jest prosta: komputer około 50 razy na sekundę tworzy obraz, rysując po kolei poziome linie na ekranie, od lewej do prawej strony. Po narysowaniu pewnej liczby takich linii (tzw. rozdzielczość pionowa komputera) cały proces zaczyna się od początku, ale wtedy układy sprzętowe (w tym wypadku ANTIC - koprocesor graficzny ATARI) zgłaszają ten fakt procesorowi, generując sygnał przerwania, którego nie może on nie zauważyć. Gwoli ścisłości należy dodać, że przez chwilkę po zakończeniu rysowania całego obrazu ekran monitora jest wygaszony, co usprawiedliwia nazwę przerwania VBLANK. Dwa kolejne słowa pamięci używane są jako wektory wskazujące adresy procedur, wywoływanych przez przerwanie wygaszania pionowego. Potrzebne są aż dwa adresy skoków, ponieważ obsługa tego wydarzenia przebiega w dwóch etapach, z których pierwszy jest wykonywany zawsze, natomiast drugi tylko wtedy, gdy system nie wykonuje akurat operacji krytycznych czasowo, o czym Informuje stan komórki CRITIC (adres 66, $42). Ograniczenie takie wynika z faktu, że wykonywanie procedur przerwań zajmuje trochę czasu, którego mogłoby zabraknąć np. na "dogadanie się" komputera z urządzeniami peryferyjnymi. W pierwszym etapie systemowej obsługi VBLANK zwiększane są wartości, zawarte w komórkach zegara systemowego (adres 18-20, $12-$14). obsługiwany jest tzw. "tryb przyciągania uwagi" (patrz adres 77, $4d) oraz licznik programowy nr 1. W drugim etapie obsługi przerwania wygaszania pionowego aktualizowane są liczniki o numerach od 2 do 5, w komórce CH (adres 764, $02fc) umieszczany jest kod naciśniętego klawisza oraz, co ważne, do rejestrów sprzętowych przepisywane są wartości z tzw. rejestrów-cieni. Tu drobna uwaga: ponieważ niektóre z rejestrów sprzętowych ATARI wymagają odświeżania, to wartości, które powinny być do nich zapisywane przechowuje się w pamięci RAM i stamtąd też są one przenoszone do rejestrów sprzętowych. Wiedząc, że takie przenoszenie zachodzi podczas każdego przerwania VBLANK łatwo się domyślić, że nie ma większego sensu modyfikacja bezpośrednio rejestrów przypisanych układom komputera - i tak system zmienia je w zależności od cieni.
Wektor pierwszej, tak zwanej natychmiastowej, fazy obsługi przerwania VBLANK.
Wektor drugiej, tak zwanej opóźnionej, fazy obsługi przerwania VBLANK. Oczywiście nic nie stoi na przeszkodzie temu, aby zainstalować własną procedurę obsługi przerwania wygaszania pionowego, trzeba jedynie pamiętać o kilku, związanych z tym regułach. Przede wszystkim pamiętajmy, że nie jesteśmy sami, nie wolno nam postępować tak, jak zaleca większość "fachowców", którzy twierdzą, że obsługę opisywanego przerwania należy kończyć skokiem pod adres, odpowiednio, $e45f (faza pierwsza) lub $e462 (faza druga). Byłoby to niezłe rozwiązanie, ponieważ, o czym dotąd nie wspomniałem, systemowa procedura rozpoznania źródła przerwania odkłada na stos rejestry procesora, a wyżej wymienione procedury odtwarzają te rejestry w odpowiedniej kolejności, gdyby nie pewne ale. W pamięci komputera może znajdować się program rezydentny, który zainstalował własną procedurę obsługi przerwania VBLANK i jej wykonanie należy umożliwić. Na wszelki wypadek trzeba więc przy tworzeniu naszych procedur zapamiętać adresy, wskazywane przez wektory VVBLKI i WBLKD i kończyć własne procedury skokiem właśnie do nich. Jest to o tyle bezpieczne, że nawet jeśli żaden program nie zmodyfikował dotąd wektorów procedur obsługi przerwania, wykonamy skok pod adresy $e45f i $e462, zainicjowane przez OS podczas włączania komputera. W jaki sposób ustawić własne adresy procedur? Pytanie, wbrew pozorom, nie jest tak banalne, na jakie wygląda. Nie wystarczy po prostu wpisać w odpowiednie komórki pamięci adresów naszych procedur. Trzeba liczyć się z tym, że pomiędzy wpisaniem jednego i drugiego bajtu adresu może wystąpić przerwanie wygaszania pionowego. Oczywiście zostanie wywołana procedura obsługi, której adres nie został jeszcze prawidłowo ustawiony i system "pójdzie w maliny"... Rozwiązania są w tym wypadku dwa. Po pierwsze, można skorzystać z systemowej procedury ustawiania adresu przerwania VBLANK, o nazwie SETVBV (adres $e45c), która zatroszczy się o to, by nie zaszła opisana wyżej, makabryczna sytuacja. Oto. Jak to zrobić: vvblkd equ $0224 setvbv equ $e45c ustaw lda vvblkd sta stary lda vvblkd+1 sta stary+1 zapamiętaj adres lda #7 chodzi o WBLKD ldy <moja młodszy bajt adresu ldx >moja starszy bajt adresu jsr setvbv * tu dalsza część programu * ... oddaj lda #7 ldy stary ldx stary+l jmp setvbv moja equ * * ... * tu procedura obsługi VBLANK * zakończona rozkazem... jmp (stary) stary org *+2 endDrugie rozwiązanie, to samodzielne ustawienie adresu tak, aby przerwanie nie "złapało" nas w połowie roboty: clock equ $14 vvblkd equ $0224 ustaw lda vvblkd sta stary lda vvblkd+1 sta stary+l zapamiętaj adres lda clock czekaj cmp clock beq czekaj czekaj, aż się zmieni lda <moja sta vvblkd lda >moja sta vvblkd+1 ustaw nowy adres * tu dalsza część programu * ... oddaj lda clock czeko cmp clock beq czeko lda stary sta vvblkd lda stary+l sta vvblkd+1 moja equ * * ... * tu procedura obsługi VBLANK * zakończona rozkazem... jmp (stary) stary org *+2 endByć może ten sposób nie jest tak elegancki, jak odwoływanie się do procedur systemowych, ale równie skuteczny. Dlaczego? Jak napisałem powyżej, podczas obsługi przerwania VBLANK system między innymi zwiększa trzybajtowy zegar systemowy, którego najmniej znaczący (tzn. zwiększany przez każde przerwanie wygaszania pionowego) bajt jest pod adresem 20 czyli $14. Wystarczy odczytać ten bajt i porównywać przechowaną wartość ze świeżo odczytaną dopóki są one równe, nie wolno nic zrobić. Kiedy wskazanie zegara się zmieni, oznacza to, że włanie skończyło się przerwanie VBLANK, a następne będzie dopiero za chwilę. Oczywiście, mówiąc "chwilę", mam na myśli czas, w którym procesor spokojnie zdąży podmienić wektor i nie należy się obawiać żadnych, nieprzewidzianych konsekwencji. W przerwaniu VBLANK można robić wiele interesujących rzeczy, np. obsługiwać animację, sprawdzać ruchy joysticka, czy też po prostu mrugać kursorem. Sposób jego wykorzystania zależy od inwencji programisty. Ja zaś chciałbym wspomnieć o jeszcze jednym zagadnieniu, związanym z przerwaniem wygaszania pionowego. Jeśli w programie, który piszemy, zmieniamy dynamicznie wygląd ekranu, warto synchronizować procedury wyświetlania z przerwaniem VBLANK, ponieważ zapobiegnie to efektowi mrugania wyświetlanego obrazu. I na koniec limity czasowe dla obu faz obsługi VBLANK. Etap pierwszy powinien trwać nie dłużej niż 3800 cykli maszynowych, drugi zaś nie dłużej niż 20000 cykli maszynowych. Dane te podaję za I. Chadwick "Mapping The Atari". Jarosław Syrylak
|