   #Start Prev Next Contents

   Jak pisac programy w jezyku asembler?

Czesc 7 - Porty, czyli lacznosc miedzy procesorem a innymi urzadzeniami

   Nie zastanawialiscie sie kiedys, jak procesor komunikuje sie z tymi
   wszystkimi urzadzeniami, ktore znajduja sie w komputerze?
   Teraz zajmiemy sie wlasnie sposobem, w jaki procesor uzyskuje dostep
   do urzadzen zewnetrznych (zewnetrznych dla procesora, niekoniecznie
   tych znajdujacych sie poza obudowa komputera).

   Procesor moze porozumiewac z urzadzeniami przez wydzielone obszary
   RAM-u. Te informacje mozna zobaczyc w Windows we wlasciwosciach
   (prawie) kazdego urzadzenia, na karcie "Zasoby", pod haslem "Zakres
   pamieci".

   Mimo iz niekiedy sporo urzadzen zajmuje po jakims skrawku pamieci, to
   jednak nie wszystkie. Glownym sposobem komunikacji ciagle pozostaja
   porty ("Zasoby" - "Zakres wejscia/wyjscia").

   Porty sa to specjalne adresy, pod ktore procesor moze wysylac dane.
   Stanowia oddzielna "strefe" adresowa (16-bitowa, jak dalej zobaczymy,
   wiec najwyzszy teoretyczny numer portu wynosi 65535), choc czasami do
   niektorych portow mozna dostac sie przez pamiec RAM. Sa to porty
   mapowane do pamieci (memory-mapped), ktorymi nie bedziemy sie
   zajmowac.

   Lista przerwan Ralfa Brown'a (RBIL) zawiera plik ports.lst (ktory
   czasami trzeba osobno utworzyc - szczegoly w dokumentacji). W pliku
   tym (wygodnie jest go przegladac na przyklad programem ii.exe,
   dolaczanym do RBIL) znajduja sie szczegoly dotyczace calkiem sporej
   liczby portow odpowiadajacym roznym urzadzeniom. I tak, mamy na
   przyklad
     * Kontrolery DMA
     * Programowalny kontroler przerwan (Programmable Interrupt
       Controller, PIC)
     * Programowalny czasomierz (Programmable Interval Timer, PIT)
     * Kontroler klawiatury
     * CMOS
     * SoundBlaster i inne karty dzwiekowe
     * Karty graficzne i inne karty rozszerzen (na przyklad modem)
     * Porty COM, LPT
     * Kontrolery dyskow twardych
     * i wiele, wiele innych...

   No dobrze, wiemy co ma ktory port i tak dalej, ale jak z tego
   skorzystac?

   Procesor posiada dwie instrukcje przeznaczone specjalnie do tego celu.
   Sa to IN i OUT.
   Ich podstawowa skladnia wyglada tak:
        in al/ax/eax, numer_portu
        out numer_portu, al/ax/eax

   Uwagi:
    1. Jesli numer_portu jest wiekszy niz 255, to w jego miejsce musimy
       uzyc rejestru DX
    2. Do operacji na portach nie mozna uzywac innych rejestrow niz AL,
       AX lub EAX.
    3. Wczytane ilosci bajtow zaleza od rejestru, a ich pochodzenie - od
       rodzaju portu:
          + jesli port num jest 8-bitowy, to
            IN AL, num wczyta 1 bajt z portu o numerze num
            IN AX, num wczyta 1 bajt z portu num (do AL) i 1 bajt z portu
            num+1 (do AH)
            IN EAX, num wczyta po 1 bajcie z portow num, num+1, num+2 i
            num+3 i umiesci w odpowiednich czesciach rejestru EAX (od
            najmlodszej)
          + jesli port num jest 16-bitowy, to
            IN AX, num wczyta 2 bajty z portu o numerze num
            IN EAX, num wczyta 2 bajty z portu o numerze num i 2 bajty z
            portu o numerze num+1
          + jesli port num jest 32-bitowy, to
            IN EAX, num wczyta 4 bajty z portu o numerze num
    4. Podobne uwagi maja zastosowane dla instrukcji OUT

   Teraz bylaby dobra pora na jakis przyklad (majac na uwadze dobro
   swojego komputera, NIE URUCHAMIAJ PONIZSZYCH KOMEND):
        in      al, 0   ; pobierz bajt z portu 0
        out     60h, eax; wyslij 4 bajty na port 60h

        mov     dx, 300 ; 300 > 255, wiec musimy uzyc DX
        in      al, dx  ; wczytaj 1 bajt z portu 300
        out     dx, ax  ; wyslij 2 bajty na port 300

   Nie rozpisywalem sie tutaj za bardzo, bo ciekawsze i bardziej
   uzyteczne przyklady znajduja sie w moich mini-kursach (programowanie
   diod na klawiaturze, programowanie glosniczka).

   Jak juz wspomnialem wczesniej, porty umozliwiaja dostep do wielu
   urzadzen. Jesli wiec chcesz poeksperymentowac, nie wybieraj portow
   zajetych na przyklad przez kontrolery dyskow twardych, gdyz zabawa
   portami moze prowadzic do utraty danych lub uszkodzenia sprzetu.
   Dlatego wlasnie w nowszych systemach operacyjnych (tych pracujacych w
   trybie chronionym, jak na przyklad Linux czy Windows) dostep do portow
   jest zabroniony dla zwyklych aplikacji (o prawa dostepu do portow
   trzeba prosic system operacyjny).
   Jak wiec dzialaja na przyklad stare DOS-owe gry? Odpowiedz jest
   prosta: nie dzialaja w trybie chronionym. System uruchamia je w trybie
   udajacym tryb rzeczywisty (taki, w jakim pracuje DOS), co umozliwia im
   pelna kontrole nad sprzetem.
   Wszystkie programy, ktore dotad pisalismy tez uruchamiaja sie w tym
   samym trybie, wiec maja swobode w dostepie na przyklad do glosniczka
   czy karty dzwiekowej. Co innego programy pisane w nowszych
   kompilatorach na przyklad jezyka C - tutaj moze juz byc problem. Ale
   na szczescie my nie musimy sie tym martwic...

   Jeszcze jeden ciekawy przyklad - uzywanie CMOSu. CMOS ma 2 podstawowe
   porty: 70h, zwany portem adresu i 71h, zwany portem danych. Operacje
   sa proste i skladaja sie z 2 krokow:
    1. Na port 70h wyslij numer komorki (1 bajt), ktora chcesz odczytac
       lub zmienic. Polecam plik cmos.lst z RBIL, zawierajacy szczegolowy
       opis komorek CMOS-u
    2. Na port 71h wyslij dane, jesli chcesz zmienic komorke lub z portu
       71h odczytaj dane, jesli chcesz odczytac komorke

   Oto przyklad. Odczytamy tutaj czas w komputerze, a konkretnie -
   sekundy:
        mov     al, 0
        out     70h, al
        out     0edh, al
        in      al, 71h

   Wszystko jasne, oprocz tej dziwnej komendy: OUT 0edh, al. Jak
   spojrzycie w ports.lst, ten port jest (jako jeden z dwoch) opisany
   jako "dummy port for delay". Czyli nic nie robi, poza opoznianiem.
   Po co to komu, pytacie?
   Przy wspolczesnych czestotliwosciach procesorow, CMOS (jak z reszta i
   inne uklady) moze po prostu nie zdazyc z odpowiedzia na nasza prosbe,
   gdyz od chwili wyslania numeru komorki do chwili odczytania danych
   mija za malo czasu. Dlatego robimy sobie przerwe na kilkanascie taktow
   zegara procesora.
   Kiedys miedzy operacjami na CMOSie zwyklo sie pisac JMP short $+2, co
   tez oczywiscie nie robilo nic, poza zajmowaniem czasu (to jest po
   prostu skok o 2 bajty do przodu od miejsca, gdzie zaczyna sie ta
   dwubajtowa instrukcja, czyli skok do nastepnej instrukcji), ale ta
   operacja juz nie trwa wystarczajaco dlugo, aby ja dalej stosowac.

   W dzisiejszych czasach porty juz nie sa tak czesto uzywane, jak byly
   kiedys. Jest to spowodowane przede wszystkim wspomnianym trybem
   chronionym oraz tym, ze wszystkie urzadzenia maja juz wlasne
   sterowniki (majace wieksze uprawnienia do manipulowania sprzetem),
   ktore zajmuja sie wszystkimi operacjami I/O. Programista musi jedynie
   uruchomic odpowiednia funkcje i niczym sie nie przejmowac.

   Dawniej, portow uzywalo sie do sterowania grafika czy wysylania
   dzwiekow przez glosniczek lub karty dzwiekowe. Teraz tym wszystkim
   zajmuje sie za nas system operacyjny. Dzieki temu mozemy sie uchronic
   przed zniszczeniem sprzetu.

   Mimo iz rola portow juz nie jest taka duza, zdecydowalem sie je
   omowic, gdyz po prostu czasami moga sie przydac. I nie bedziecie
   zdziwieni, gdy ktos pokaze wam kod z jakimis dziwnymi instrukcjami IN
   i OUT...

   Szczegoly dotyczace instrukcji dostepu do portow takze znajdziecie,
   jak zwykle, u AMD i Intela.

   Milej zabawy.

   Poprzednia czesc kursu (klawisz dostepu 3)
   Kolejna czesc kursu (klawisz dostepu 4)
   Spis tresci off-line (klawisz dostepu 1)
   Spis tresci on-line (klawisz dostepu 2)
   Ulatwienia dla niepelnosprawnych (klawisz dostepu 0)
     _________________________________________________________________

Cwiczenia

    1. Zapoznaj sie z opisem CMOSu i napisz program, ktory wyswietli
       biezacy czas w postaci gg:mm:ss (z dwukropkami). Pamietaj o
       umieszczeniu opoznien w swoim programie.
