MINI KURS PISANIA PROGRAM艁W TSR W ASEMBLERZE
2. PRZERWANIA W PROGRAMACH TSR, PAMI悤 I ZEGAR CMOS
W poprzednich odcinkach kursu dowiedzieli艣my si臋, co to jest TSR i jak
si臋 go instaluje w pami臋ci. Przyszed艂 czas na zaprz臋gni臋cie naszego rezydenta
do bardziej konkretnych zada艅, dobrym przyk艂adem niech b臋dzie napisanie
prostego programu instaluj膮cego si臋 w pami臋ci i pokazuj膮cego aktualn膮
sekund臋, taka ma艂a wprawka przed pe艂nym zegarem, kt贸ry ka偶dy z was b臋dzie
m贸g艂 spokojnie sam napisa膰 po przeczytaniu tego odcinka.
Co nam tym razem b臋dzie potrzebne ? Oczywi艣cie, przerwanie zegara,
wykonywane z cz臋stotliwo艣ci膮 18.2 Hz (czyli oko艂o 18 razy na sekund臋), a
dok艂adnie: 1193181/65536 Hz. Mo偶emy "przechwyci膰" to przerwanie, czyli
podstawi膰 swoj膮 w艂asn膮 procedur臋, kt贸r膮 komputer b臋dzie wywo艂ywa膰 ze
wspomnian膮 cz臋stotliwo艣ci膮. W naszej procedurze b臋dziemy pobiera膰 z komputera
aktualny czas i wy艣wietla膰 liczb臋 sekund w lewym g贸rnym rogu ekranu. Pojawia
si臋 tylko pytanie - po co sprawdza膰 czas a偶 18 razy na sekund臋, je偶eli mamy
wy艣wietla膰 tylko sekundy, kt贸re si臋 b臋d膮 zmienia膰 co 18 przerwa艅 ?
Najprostszym rozwi膮zaniem na oszcz臋dzenie czasu procesora jest sprawdzanie
aktualnego czasu tylko co 18 wywo艂anie naszej procedury. Jednak偶e mo偶emy
post膮pi膰 jeszcze inaczej - wy艣wietla膰 sekundnik na ekranie tylko wtedy, gdy
jego wskazanie jest r贸偶ne od poprzedniego. To nam oszcz臋dzi mocy procesora
traconej za przez ka偶d膮 sekund臋 na wy艣wietlaniu tej samej liczby 18 razy.
My jednak w programie przyk艂adowym zrezygnujemy z takiej optymalizacji, aby
nie zaciemnia膰 kodu, ka偶dy mo偶e to sam po膰wiczy膰. Jeszcze jedna dygresja - po
dokonaniu swoich dzia艂a艅 nasza procedura musi zwraca膰 sterowanie do
oryginalnej (czyli pod adres, kt贸ry odczytamy w czasie instalowania si臋
naszego TSRa, dla skr贸cenia opisu nazywa si臋 cz臋sto ten adres "wektorem
przerwania").
Teraz opis dw贸ch przydatnych funkcji, kt贸re nam udost臋pnia DOS (czyli
przerwanie 21h):
Funkcja 25h
Nazwa: Ustalanie adresu kodu obs艂ugi przerwania
Wywo艂anie: AH=25h
AL - numer przerwania
DS:DX - adres procedury obs艂uguj膮cej przerwanie
Powr贸t: Brak
Opis: Funkcja ustawia now膮 procedur臋 obs艂ugi przerwania o numerze
podanym w AL. Adres procedury obs艂ugi przerwania powinien by膰
przekazany w DS:DX.
Funkcja 35h
Nazwa: Pytanie o adres kodu obs艂ugi przerwania
Wywo艂anie: AH=35h
AL - numer przerwania
Powr贸t: ES:BX - adres procedury obs艂ugi przerwania
Opis: Funkcja zwraca adres procedury obs艂ugi przerwania o numerze
podanym w AL.
Dobra, mamy ju偶 wiadomo艣ci o tym, jak przechwytywa膰 przerwanie po
zapami臋taniu adresu oryginalnej procedury obs艂ugi. Pytanie: no to kt贸re to
w艂a艣ciwie jest przerwanie zegarowe ? Ot贸偶 jest to przerwanie nr 8, czyli
IRQ0. Nale偶y si臋 jednak drobne wyja艣nienie: IRQ0 oznacza, 偶e do kontrolera
przerwa艅 (a s膮 takie dwa uk艂ady na p艂ycie g艂贸wnej komputera) do linii nr 0
przychodz膮 informacje od uk艂adu zegarowego, kt贸ry na t膮 lini臋 wystawia sygna艂
偶膮dania przerwania w艂a艣nie 18 razy na sekund臋. Podobnie do IRQ0 pod艂膮czona
jest klawiatura, IRQ5 cz臋sto karta muzyczna i tak dalej. Numer przerwania
obs艂uguj膮cego lini臋 IRQx to x+8, czyli przerwanie zegarowe ma numer 8,
przerwanie klawiatury - nr 9 i tak dalej. Drugim kontrolerem nie b臋dziemy si臋
na razie zajmowa膰, zaznacz臋 tylko, 偶e obs艂uguje on przerwania IRQ8 do IRQ15,
a numery przerwa艅 od drugiego kontrolera zaczynaj膮 si臋 dla zmy艂ki od 40h.
Kolejna sprawa: jak odczyta膰 aktualn膮 sekund臋 ? Jest kilka sposob贸w, my
skorzystamy z bezpo艣redniego dost臋pu do zegara CMOS umieszczonego na p艂ycie
g艂贸wnej komputera. Jest on widziany w przestrzeni adresowej jako dwa kolejne
porty: o numerze 70h oraz 71h, dost臋pne dla programisty poprzez instrukcje:
out i in. Instrukcja 'out' s艂u偶y do wysy艂ania danych do portu, instrukcja
'in' do czytania z portu. W naszym przypadku b臋d膮 to instrukcje: out 70h,al
oraz in al,71h. Pierwsz膮 z nich wy艣lemy do zegara CMOS numer kom贸rki, kt贸ra
nas interesuje (o tym dalej), a drug膮 odczytamy jej zawarto艣膰. Ca艂y fragment
kodu czytaj膮cy aktualn膮 sekund臋 b臋dzie w zwi膮zku z tym wygl膮da艂 tak:
xor al,al
out 70h,al
jmp $+2
in al,71h
Instrukcja jmp $+2 powoduje drobne op贸艢nienie wymagane do poprawnej
wsp贸艂pracy z zegarem CMOS, natomiast xor al,al jest r贸wnowa偶ne mov al,0 -
czyli po prostu do rejestru AL wpisuje zero. Po wykonaniu wy偶ej podanego
bloku 4 rozkaz贸w otrzymamy aktualn膮 sekund臋 w AL w kodzie BCD, kt贸ry nale偶y
jeszcze przekonwertowa膰 na kody dw贸ch znak贸w liczby. Jak to jest zrobione w
praktyce ujrzycie za chwil臋 w listingu rezydenta. Jeszcze tylko troch臋 wi臋cej
informacji o uk艂adzie CMOS, w kt贸rym opr贸cz zegara zawarta jest te偶 pami臋膰
przechowuj膮ca najwa偶niejsze ustawienia naszych komputer贸w (czyli ca艂膮
zawarto艣膰 SETUPu). Oto adresy i funkcje kolejnych kom贸rek, do kt贸rych mo偶emy
si臋 odwo艂ywa膰 (po opisy szczeg贸艂owe odsy艂am do ksi膮偶ek):
0 aktualna sekunda zegara czasu rzeczywistego (RTC) w kodzie BCD
1 sekunda ustawienia budzika w kodzie BCD
2 aktualna minuta w BCD
3 minuta ustawienia budzika w BCD
4 aktualna godzina RTC w BCD
5 godzina ustawienia budzika w BCD
6 dzie艅 tygodnia (1=niedziela,2=poniedzia艂ek itd.)
7 dzie艅 miesi膮ca w BCD
8 miesi膮c w BCD
9 rok w BCD (ostatnie dwie cyfry)
0ah RTC rejestr stanu A
0bh RTC rejestr stanu B
0ch RTC rejestr stanu C
0dh RTC rejestr stanu D
0eh bajt stanu ustawiany przez POST
0fh pow贸d wy艂膮czenia
10h typ stacji dysk贸w w systemie
11h zarezerwowane
12h typ twardego dysku
13h zarezerwowane
14h bajt wyposa偶enia komputera
I tak dalej. Jest tych kom贸rek 256 i kogo bardziej interesuj膮, mo偶e
zawsze zajrze膰 do literatury (np. podanej ju偶 wcze艣niej ksi膮偶ki: "Jak pisa膰
wirusy"). Kolejna sprawa: jak wypisa膰 warto艣膰 na ekranie nie u偶ywaj膮c do tego
przerwania DOSu (u偶ywanie przerwa艅 w naszej procedurze rezydentnej jest
bardzo ryzykowne, o tym b臋dzie powiedziane dok艂adniej w dalszych cz臋艣ciach
kursu) ? Ot贸偶 jest spos贸b, nale偶y kody znak贸w do wypisania "wcisn膮膰"
bezpo艣rednio w obszar pami臋ci ekranu, na kartach VGA, CGA, EGA itp. zaczyna
si臋 ona od pocz膮tku segmentu B800h, natomiast na karcie Hercules (HGC) od
B000h. Pod tymi adresami mamy dost臋p do kodu pierwszego znaku na ekranie
(czyli tego w lewym g贸rnym rogu), w nast臋pnym bajcie le偶y atrybut tego znaku,
dalej kod drugiego znaku, jego atrybut itd. Kolory znak贸w mo偶emy obliczy膰
podstawiaj膮c odpowiednie bity w bajcie atrybut贸w:
nr bitu: 7 6 5 4 3 2 1 0
znaczenie: K R G B i r g b
K to blink, czyli migotanie znaku (znak miga gdy bit K=1), i to
intensity - jasno艣膰 znaku (0=ciemniejszy, 1=ja艣niejszy), RGB to kolejne
sk艂adowe kolor贸w t艂a, natomiast rgb to sk艂adowe kolor贸w znaku. Przyk艂ad:
potrzebujemy bajt atrybutu oznaczaj膮cy jasnoczerwone znaki na czarnym tle,
nie migaj膮ce:
nr bitu: 7 6 5 4 3 2 1 0
znaczenie: K R G B i r g b
warto艣膰: 0 0 0 0 1 1 0 0
艂 膭呐呐 艂 膭牧牧腸zerwony
znak nie 哪呐 艂 膭jasny
miga t艂o czarne
Czyli wychodzi na to, 偶e poszukiwany atrybut znaku to 0ch. Mo偶na wpisa膰
go w pami臋膰 ekranu oddzielnie, po wpisaniu kodu znaku, jednak my te dwie
rzeczy zrobimy jednocze艣nie - wpisuj膮c od razu ca艂e s艂owo 16-bitowe rozkazem
stosw, umieszczaj膮cym warto艣膰 rejestru AX pod adresem ES:DI i zwi臋kszaj膮cym
DI o 2 - tak, 偶e wskazuje od razu na nast臋pny znak. Po uruchomieniu programu
b臋dziecie mogli si臋 przekona膰, 偶e czas zawarty w zegarze CMOS spieszy si臋
nieznacznie wzgl臋dem czasu DOSowego (np. pokazywanego przez Dos Navigatora,
Nortona Commandera itp.), poniewa偶 przy uruchamianiu komputera DOS odczytuje
zawarto艣膰 CMOSa i troch臋 czasu mu zajmuje ustawienie swojego zegara - przez
to si臋 sp贸艢nia. Natomiast po wy艂膮czeniu komputera zegar CMOS chodzi sobie
jakby nigdy nic - jego zasilanie jest podtrzymywane bateryjnie. Ale do艣膰
gl臋dzenia, przyszed艂 czas na listing:
----------> Obci膮膰 <----------
.model tiny
.code
.386
org 100h
Start:
jmp Instaluj
; tutaj b臋d膮 nasze zmienne:
staraproc dd 0 ; dd oznacza 4 bajty (tutaj o warto艣ci 0)
NaszaProc:
push ax ; zapami臋tujemy warto艣ci u偶ywanych rejestr贸w
push bx
push di
push es
mov ax,0b800h ; B800h - segment pami臋ci ekranu karty VGA
mov es,ax
xor di,di ; zerujemy DI - adres w pami臋ci ekranu
xor al,al ; AL=0 - kom贸rka z aktualn膮 sekund膮 w BCD
out 70h,al ; wysy艂amy do zegara CMOS
jmp $+2 ; ma艂e op贸艢nienie
in al,71h ; odczytujemy wynik z zegara CMOS
mov bl,al
and bl,0fh ; prawa po艂贸wka bajtu - prawa cyfra w BCD
add bl,'0' ; do tego dodajemy kod zera
shr al,4 ; lewa po艂贸wka bajtu - lewa cyfra w BCD
add al,'0' ; do tego te偶 dodajemy kod '0'
mov ah,0ch ; atrybut napisu - jasnoczerwony na czarnym tle
stosw ; i rzucamy na ekran pierwsz膮 cyfr臋
mov al,bl
stosw ; potem drug膮
pop es
pop di
pop bx
pop ax
jmp dword ptr cs:[staraproc] ; skok do oryginalnej procedury
; koniec cz臋艣ci rezydentnej
Instaluj:
mov ax,3508h ; 35h: pobranie wektora przerwania
int 21h ; wynik wpad艂 do ES:BX
mov word ptr cs:[staraproc],bx ; trzeba jeszcze go gdzies zapamietac
mov word ptr cs:[staraproc +2],es
mov ax,2508h ; 25h: ustawienie wektora przerwania
mov dx,offset NaszaProc ; DS:DX - wektor naszej procedury
int 21h
mov ah,9 ; 09h: wydruk napisu na ekran
mov dx,offset Napis
int 21h
mov dx,offset Instaluj ; do DX wpisujemy adres pierwszego bajtu,
int 27h ; kt贸ry ma by膰 zwolniony, wcze艣niejsze
; zostaj膮 w pami臋ci na sta艂e
Napis db 'Program zainstalowany w pami臋ci.',13,10,'$'
end Start
----------> Obci膮膰 <----------
W nast臋pnym odcinku dowiemy si臋, jak naszego rezydenta wyrzuci膰 z
pami臋ci i do tego jeszcze kilka innych przydatnych rzeczy.
Wyszukiwarka
Podobne podstrony:
Asembler w TSR KURS2kurs2 (2)kurs2kurs2kurs2wi臋cej podobnych podstron