                MINI KURS PISANIA PROGRAMW TSR W ASEMBLERZE

2. PRZERWANIA W PROGRAMACH TSR, PAMI I ZEGAR CMOS

     W  poprzednich  odcinkach kursu dowiedzielimy si, co to jest TSR i jak
si go instaluje w pamici. Przyszed czas na zaprzgnicie naszego rezydenta
do  bardziej  konkretnych  zada,  dobrym  przykadem  niech bdzie napisanie
prostego  programu  instalujcego  si  w  pamici  i  pokazujcego  aktualn
sekund,  taka  maa  wprawka  przed penym zegarem, ktry kady z was bdzie
mg spokojnie sam napisa po przeczytaniu tego odcinka.

     Co  nam  tym  razem  bdzie  potrzebne  ? Oczywicie, przerwanie zegara,
wykonywane  z  czstotliwoci  18.2  Hz  (czyli okoo 18 razy na sekund), a
dokadnie:  1193181/65536  Hz.  Moemy  "przechwyci"  to  przerwanie,  czyli
podstawi   swoj  wasn  procedur,  ktr  komputer  bdzie  wywoywa  ze
wspomnian czstotliwoci. W naszej procedurze bdziemy pobiera z komputera
aktualny  czas i wywietla liczb sekund w lewym grnym rogu ekranu. Pojawia
si  tylko  pytanie - po co sprawdza czas a 18 razy na sekund, jeeli mamy
wywietla   tylko   sekundy,  ktre  si  bd  zmienia  co  18  przerwa ?
Najprostszym  rozwizaniem  na  oszczdzenie czasu procesora jest sprawdzanie
aktualnego  czasu  tylko  co  18  wywoanie naszej procedury. Jednake moemy
postpi  jeszcze  inaczej - wywietla sekundnik na ekranie tylko wtedy, gdy
jego  wskazanie  jest  rne od poprzedniego. To nam oszczdzi mocy procesora
traconej  za  przez  kad  sekund na wywietlaniu tej samej liczby 18 razy.
My  jednak  w programie przykadowym zrezygnujemy z takiej optymalizacji, aby
nie zaciemnia kodu, kady moe to sam powiczy. Jeszcze jedna dygresja - po
dokonaniu   swoich   dziaa  nasza  procedura  musi  zwraca  sterowanie  do
oryginalnej  (czyli  pod  adres,  ktry  odczytamy  w czasie instalowania si
naszego  TSRa,  dla  skrcenia  opisu  nazywa  si czsto ten adres "wektorem
przerwania").

     Teraz  opis  dwch  przydatnych funkcji, ktre nam udostpnia DOS (czyli
przerwanie 21h):

Funkcja 25h
Nazwa:          Ustalanie adresu kodu obsugi przerwania
Wywoanie:      AH=25h
                AL - numer przerwania
                DS:DX - adres procedury obsugujcej przerwanie
Powrt:         Brak
Opis:           Funkcja ustawia now procedur obsugi przerwania o numerze
                podanym w AL. Adres procedury obsugi przerwania powinien by
                przekazany w DS:DX.

Funkcja 35h
Nazwa:          Pytanie o adres kodu obsugi przerwania
Wywoanie:      AH=35h
                AL - numer przerwania
Powrt:         ES:BX - adres procedury obsugi przerwania
Opis:           Funkcja zwraca adres procedury obsugi przerwania o numerze
                podanym w AL.

     Dobra,  mamy  ju  wiadomoci  o  tym,  jak  przechwytywa przerwanie po
zapamitaniu  adresu  oryginalnej  procedury obsugi. Pytanie: no to ktre to
waciwie  jest  przerwanie  zegarowe  ?  Ot jest to przerwanie nr 8, czyli
IRQ0.  Naley  si  jednak drobne wyjanienie: IRQ0 oznacza, e do kontrolera
przerwa  (a  s  takie dwa ukady na pycie gwnej komputera) do linii nr 0
przychodz informacje od ukadu zegarowego, ktry na t lini wystawia sygna
dania  przerwania  wanie  18 razy na sekund. Podobnie do IRQ0 podczona
jest  klawiatura,  IRQ5  czsto  karta muzyczna i tak dalej. Numer przerwania
obsugujcego  lini  IRQx  to  x+8,  czyli  przerwanie  zegarowe ma numer 8,
przerwanie klawiatury - nr 9 i tak dalej. Drugim kontrolerem nie bdziemy si
na  razie zajmowa, zaznacz tylko, e obsuguje on przerwania IRQ8 do IRQ15,
a numery przerwa od drugiego kontrolera zaczynaj si dla zmyki od 40h.

     Kolejna  sprawa: jak odczyta aktualn sekund ? Jest kilka sposobw, my
skorzystamy  z  bezporedniego dostpu do zegara CMOS umieszczonego na pycie
gwnej  komputera. Jest on widziany w przestrzeni adresowej jako dwa kolejne
porty:  o  numerze 70h oraz 71h, dostpne dla programisty poprzez instrukcje:
out  i  in.  Instrukcja  'out' suy do wysyania danych do portu, instrukcja
'in'  do  czytania z portu. W naszym przypadku bd to instrukcje: out 70h,al
oraz  in  al,71h. Pierwsz z nich wylemy do zegara CMOS numer komrki, ktra
nas  interesuje (o tym dalej), a drug odczytamy jej zawarto. Cay fragment
kodu czytajcy aktualn sekund bdzie w zwizku z tym wyglda tak:

  xor  al,al
  out  70h,al
  jmp  $+2
  in   al,71h

     Instrukcja  jmp  $+2  powoduje  drobne  opnienie wymagane do poprawnej
wsppracy  z  zegarem  CMOS,  natomiast xor al,al jest rwnowane mov al,0 -
czyli  po  prostu  do  rejestru  AL wpisuje zero. Po wykonaniu wyej podanego
bloku  4  rozkazw otrzymamy aktualn sekund w AL w kodzie BCD, ktry naley
jeszcze  przekonwertowa  na kody dwch znakw liczby. Jak to jest zrobione w
praktyce ujrzycie za chwil w listingu rezydenta. Jeszcze tylko troch wicej
informacji  o  ukadzie  CMOS, w ktrym oprcz zegara zawarta jest te pami
przechowujca   najwaniejsze   ustawienia  naszych  komputerw  (czyli  ca
zawarto  SETUPu). Oto adresy i funkcje kolejnych komrek, do ktrych moemy
si odwoywa (po opisy szczegowe odsyam do ksiek):

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=poniedziaek itd.)
7       dzie miesica w BCD
8       miesic 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     powd wyczenia
10h     typ stacji dyskw w systemie
11h     zarezerwowane
12h     typ twardego dysku
13h     zarezerwowane
14h     bajt wyposaenia komputera

     I  tak  dalej.  Jest  tych  komrek 256 i kogo bardziej interesuj, moe
zawsze  zajrze  do literatury (np. podanej ju wczeniej ksiki: "Jak pisa
wirusy"). Kolejna sprawa: jak wypisa warto na ekranie nie uywajc do tego
przerwania  DOSu  (uywanie  przerwa  w  naszej  procedurze rezydentnej jest
bardzo  ryzykowne,  o  tym bdzie powiedziane dokadniej w dalszych czciach
kursu)  ?  Ot  jest  sposb,  naley  kody  znakw  do  wypisania "wcisn"
bezporednio  w  obszar pamici ekranu, na kartach VGA, CGA, EGA itp. zaczyna
si  ona  od  pocztku  segmentu B800h, natomiast na karcie Hercules (HGC) od
B000h.  Pod  tymi  adresami  mamy  dostp do kodu pierwszego znaku na ekranie
(czyli tego w lewym grnym rogu), w nastpnym bajcie ley atrybut tego znaku,
dalej  kod  drugiego  znaku,  jego atrybut itd. Kolory znakw moemy obliczy
podstawiajc odpowiednie bity w bajcie atrybutw:

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=janiejszy),  RGB to kolejne
skadowe  kolorw  ta,  natomiast  rgb  to skadowe kolorw znaku. Przykad:
potrzebujemy  bajt  atrybutu  oznaczajcy jasnoczerwone znaki na czarnym tle,
nie migajce:

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
               czerwony
znak nie       jasny
miga      to czarne

     Czyli  wychodzi na to, e poszukiwany atrybut znaku to 0ch. Mona wpisa
go  w  pami  ekranu  oddzielnie,  po wpisaniu kodu znaku, jednak my te dwie
rzeczy  zrobimy jednoczenie - wpisujc od razu cae sowo 16-bitowe rozkazem
stosw,  umieszczajcym  warto rejestru AX pod adresem ES:DI i zwikszajcym
DI  o 2 - tak, e wskazuje od razu na nastpny znak. Po uruchomieniu programu
bdziecie  mogli  si  przekona,  e czas zawarty w zegarze CMOS spieszy si
nieznacznie  wzgldem  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  spnia.  Natomiast  po wyczeniu komputera zegar CMOS chodzi sobie
jakby  nigdy  nic  -  jego  zasilanie jest podtrzymywane bateryjnie. Ale do
gldzenia, przyszed czas na listing:

----------> Obci <----------
.model tiny
.code
.386
org 100h

Start:
  jmp  Instaluj

; tutaj bd nasze zmienne:
staraproc dd 0               ; dd oznacza 4 bajty (tutaj o wartoci 0)

NaszaProc:
  push ax                    ; zapamitujemy wartoci uywanych rejestrw
  push bx
  push di
  push es
  mov  ax,0b800h             ; B800h - segment pamici ekranu karty VGA
  mov  es,ax
  xor  di,di                 ; zerujemy DI - adres w pamici ekranu
  xor  al,al                 ; AL=0 - komrka z aktualn sekund w BCD
  out  70h,al                ; wysyamy do zegara CMOS
  jmp  $+2                   ; mae opnienie
  in   al,71h                ; odczytujemy wynik z zegara CMOS
  mov  bl,al
  and  bl,0fh                ; prawa powka bajtu - prawa cyfra w BCD
  add  bl,'0'                ; do tego dodajemy kod zera
  shr  al,4                  ; lewa powka 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 czci 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                   ; ktry ma by zwolniony, wczeniejsze
                             ; zostaj w pamici na stae

Napis  db 'Program zainstalowany w pamici.',13,10,'$'

end Start
----------> Obci <----------

     W  nastpnym  odcinku  dowiemy  si,  jak  naszego  rezydenta wyrzuci z
pamici i do tego jeszcze kilka innych przydatnych rzeczy.
