MINI KURS PISANIA PROGRAMŁW TSR W ASEMBLERZE
4. WADY I ZALETY MULTIPLEX INTERRUPT
Na początku wyjaśnijmy sobie o co w ogóle chodzi w tytule tej części.
Otóż Multiplex Interrupt jest to jedno z przerwań programowych (to znaczy nie
wywoływanych przez sprzęt, jak np. przerwanie zegara, ale tylko poprzez
instrukcję int). Ma numer 2fh i służy do bardzo wielu przydatnych rzeczy a
w szczególności niesie pomoc w programach rezydentnych. Cała istota Multiplex
Interrupt (w skrócie MxI) polega na utworzeniu "łańcucha", do którego
dopinają się kolejne programy wykorzystujące je - TSRy. Każdy program ma
przydzielony swój numer identyfikacyjny, po którym może poznać, czy odwołanie
MxI dotyczy tego rezydenta, czy jakiegoś innego. W trakcie instalacji TSR
odczytuje wektor przerwania 2fh i ustawia nowy na swoją procedurę. Teraz
kiedy przyjdzie przerwanie i w rejestrze AH jest jego numer identyfikacyjny
to oznacza, że do niego przyszło zlecenie (o tym będzie dalej) i on je ma
obsłużyć. Jeżeli w AH jest inny numer, TSR przekazuje sterowanie pod stary
adres (zapamiętany podczas instalacji). Powyższe tłumaczenie jest dość
zawiłe, dlatego podam trochę konkretów:
Przerwanie 2Fh
Nazwa: Obsługa równoczesnych procesów
Wywołanie: AH = numer procesu (czyli ID TSRa)
01h - rezydentna część polecenia PRINT
02h - rezydentna część polecenia ASSIGN
03h - rezydentna część polecenia SHARE
80h-0ffh - dostępne dla innych procesów
AL = 0
Powrót: AL - stan zainstalowania
00h - nie zainstalowany, można zainstalować
01h - nie zainstalowany, nie można zainstalować
0ffh - zainstalowany
Opis: Przerwanie organizuje równoczesną pracę programów
rezydentnych dostępnych z dowolnego procesu. Pierwotnie
dotyczyło tylko polecenia systemowego PRINT. Każdy proces
instaluje się w kolejce (poprzez kolejne przechwytywanie
tego przerwania). W przypadku wywołania zlecenia proces
sprawdza, czy zlecenie go dotyczy, jeśli nie to oddaje
sterowanie poprzedniemu w kolejce. W rejestrze AL
przekazywany jest kod zlecenia. Standardowo zlecenie numer 0
oznacza pytanie o to, czy program jest zainstalowany.
Z powyższego opisu widzimy, jak prosta jest zasada działania MxI, wszystkie
rezydentne polecenia DOSu mają wbudowaną obsługę swoich funkcji przez to
przerwanie (np. możemy poleceniu PRINT kazać zatrzymać wszystkie wydruki znając
numer zlecenia, które mamy mu przekazać), na przykład:
mov ax,0103h ; 01-PRINT, 03-zatrzymanie drukowania
int 2fh
Działanie Multiplex Interrupt w naszym rezydencie zależy tylko od naszej
inwencji, poza oczywiście zleceniem nr 0, które ma przekazać informację o
zainstalowaniu programu. Wtedy możemy stwierdzić, czy TSR jest obecny w
pamięci, pomimo że po nim był instalowany inny program rezydentny, który
również przechwycił to samo przerwanie (w przypadku sekundnika przerwanie
zegara). Poza tym możemy dodać również nasze nowe zlecenia, np. zmiana
kolorów cyfr bez reinstalacji programu, podawanie segmentu, w którym jest
obecny kod TSRa i tak dalej. Przykładów można znaleŚć bez liku, jeśli tylko
dysponuje się rozwiniętą wyobraŚnią. W naszym nowym przykładowym rezydencie
(ile razy można obrabiać i ulepszać sekundnik?) zastosujemy procedurę, która
będzie "wrażliwa" na ID procesu nr 90h (dlaczego tak? wymyśliło mi się, można
podać numer od 80h w górę) i zlecenia nr 0 oraz 1. Czasem takie założenia
mogą nie przynieść spodziewanych rezultatów, gdy w pamięci będzie inny TSR
reagujący również na numer 90h - przy takich obawach można napisać funkcję
przeszukującą kolejne numery od 80h (sprawdzamy zleceniem 0, czy rezydent
jest zainstalowany) i zatrzymującą się na pierwszym wolnym. My jednak
przyjmiemy, że 90h jest dla nas wystarczający i nic się nie powtórzy.
Zlecenie nr 0 będzie służyło do sprawdzania, czy nasz rezydent jest obecny w
pamięci (czyli będziemy w AL zwracać 0ffh) oraz przy okazji czytania numeru
segmentu, w jakim jest on zainstalowany (zwracamy w BX). Natomiast zlecenie
nr 1 będzie nam podawać w ES:DI adres ciągu znaków (zakończonego znakiem
dolara, tak jak w napisach w DOSie) z wersją zainstalowanego TSRa. Sam
program rezydentny będzie realizował trywialne zadanie - podepniemy go pod
przerwanie klawiatury i przy każdym naciśnięciu klawisza będzie generowany
dŚwięk o długości zależnej od czasu naciśnięcia (czyli po stwierdzeniu
naciśnięcia włączymy dŚwięk PC Speakera, a przy puszczeniu wyłączymy). Do
tego będzie jeszcze aktywna kombinacja Alt-Ctrl-Ins, przełączająca nam dŚwięk
(na zasadzie włączony - wyłączony - włączony itd). I znów to samo - sam
program nie jest przeznaczony do używania w konkretnych celach (czy sekundnik
komuś się do czegoś przydał?), ale do zobrazowania technik pisania TSRów.
Przy usuwaniu programu rezydentnego z pamięci (nazwijmy go roboczo:
beep) należy pamiętać o sprawdzeniu MxI, czy TSR jest obecny, jak również o
odczytaniu wektora przerwania klawiatury (int 9h), ponieważ nie możemy usunąć
TSRa i odtworzyć wykorzystywanych przez niego przerwań, kiedy po nim został
zainstalowany inny rezydent (bo w ten sposób odcięlibyśmy od "funkcji
życiowych" również ten inny program). Jednak jest na to sposób - odcinamy
tylko działanie kliku i kombinacji Alt-Ctrl-Ins poprzez ustawienie
odpowiedniej flagi w obszarze TSRa (można by było też po to wymyślić nowe
zlecenie MxI, ale po co kombinować, gdy po odczytaniu numeru segmentu kodu
zleceniem 0 mamy dostęp do obszaru zmiennych beepa), nazywa się ona
'niemamnie' i gdy nie jest równa 0 to TSR zachowuje się tak, jakby go w ogóle
nie było. Gdyby beep rezerwował sobie dodatkowe bloki pamięci należało by je
również zwolnić. Pamiętajmy również o tym, aby w czasie instalacji sprawdzić,
czy przypadkiem już wcześniej beep nie był instalowany, a jeżeli tak -
wyświetlić stosowny komunikat, no i oczywiście zwolnić blok pamięci zajmowany
przez środowisko programu. Nasz TSR nie będzie tym razem sprawdzał parametrów
podanych w linii poleceń w poszukiwaniu 'u', natomiast po uruchomieniu będzie
się instalował w pamięci, a po powtórnym uruchomieniu - usuwał (lub
dezaktywował).
Po wywołaniu przez system przerwania klawiatury, pod które jesteśmy
podpięci możemy odczytać kod wciśniętego klawisza z portu 60h (in al,60h),
jest to tzw. scan-code klawisza, czyli najogólniej mówiąc jego kolejny numer
na klawiaturze. Klawisz Insert ma scan-code równy 52h, natomiast ten sam
klawisz przy zwolnieniu wysyła kod o 80h większy (z ustawionym najwyższym
bitem), czyli 0d2h. Klawiatura rozszerzona 101-klawiszowa wysyła ponadto
dodatkowe kody informujące, czy naciśnięto Ins z klawiatury numerycznej, czy
szary Ins z dodatkowego bloku - jest wtedy przed scan-code klawisza Insert
wysyłany kod 0e0h - my po odebraniu takiego kodu przekazujemy sterowanie
bezpośrednio do oryginalnej procedury. W programie beep będziemy reagować na
puszczenie klawisza Insert ze względu na samopowtarzanie przy dłuższym
naciśnięciu (gdyby TSR reagował na naciśnięcie, obserwowalibyśmy naprzemienne
włączanie i wyłączanie funkcji programu). Fakt wciśnięcia jednocześnie Alt i
Ctrl rozpoznamy badając obszar zmiennych BIOSu (komórka 0:417h, bity 2 i 3
ustawione, traktowała o tym szerzej część 3 kursu). Po rozpoznaniu
"korzystnej" kombinacji (Alt-Ctrl-Ins) zmieniamy wartość wewnętrznego
przełącznika (zmienna flipflop), po czym zwracamy sterowanie do oryginalnej
procedury obsługi przerwania klawiatury. Gdybyśmy nie chcieli tego robić (np.
przechwycić i "zdusić" wszystkie naciśnięcia klawisza X) i nie przesyłać
sterowania pod oryginalny adres (czyli do poprzedniego programu dołączonego
do int 9h, a w końcu do procedury w BIOSie wpisującej kod ASCII klawisza do
bufora klawiatury), należałoby wykonać następujący fragment kodu, wymagany do
poprawnego powrotu do głównego programu instrukcją iret:
in al,61h ;+ znak dla kontrolera klawiatury, że zakończyliśmy
mov ah,al ;+ obsługę przerwania
or al,80h ;+
out 61h,al ;+
mov al,ah ;+
out 61h,al ;+
mov al,20h ;- znak dla kontrolera przerwań
out 20h,al ;- (tzw. EOI - End Of Interrupt)
Do włączania dŚwięku w głośniku służą instrukcje:
in al,61h
or al,3 ; ustawiamy bity: 0 i 1
out 61h,al
Do wyłączania:
in al,61h
and al,0fch ; zerujemy bity: 0 i 1
out 61h,al
Na początku w trakcie instalacji TSRa możemy jeszcze ustawić wysokość
dŚwięku wysyłając 2 bajty wartości licznika do timera (który obsługuje i
zegar, i generator głośnika). Wartość licznika to: 1193181/f, f -
częstotliwość dŚwięku. Z tego wynika, że chcąc ustawić wysokość dŚwięku na
440 Hz należy ustawić licznik na 1193181/440 = 2712, czyli 0a98h. Wysyłamy
kolejno: kod operacji (0b6h) do portu 43h, następnie młodszy bajt licznika
(98h) do portu 42h, a potem starszy bajt (0ah):
mov al,0b6h
out 43h,al
mov al,98h
out 42h,al
mov al,0ah
out 42h,al
W naszym przykładowym programie beep możliwość ustawienia wysokości
dŚwięku nie została wykorzystana, możecie to zrobić w swoich programach.
Można też również pokusić się o napisanie rezydenta, który po każdym
naciśniętym klawiszu będzie zmieniał wysokość tonu, biorąc ją na przykład z
tablicy. Wtedy przy pisaniu tekstu komputer będzie grał muzykę! To tyle na
dziś, zobaczymy, co przyniesie kolejny odcinek.
Wyszukiwarka
Podobne podstrony:
kurs4kurs4 (2)Asembler w TSR KURS4więcej podobnych podstron