Poniedziałek 28 Kwiecień 2025r. Godz 00:00:00      
Postów: 251      

Assembler - Obsługa portów

Sprawa portów jest dość podobna do przerwań - istnieje jedna instrukcja do ich (przerwań) obsługi a możliwości jakie przez nią uzyskujemy są ogromne, ale warunkiem jest znajomość parametrów przerwań o czym również pisałem.
W przypadku portów istnieją dwie instrukcje - IN - pobierz z portu i OUT - wyślij na port, ale warunkiem pełnego wykorzystania tych instrukcji jest znajomość specyfikacji poszczególnych urządzeń (karta muzyczna chociażby).

Instrukcja IN (in - w) powoduje pobranie bajtu lub słowa z portu i wrzucenie go do "akumul". Można tu znaleźć analogie do pascalowskiego port i portw - gdy "akumul" jest bajtem (al) pobrany zostaje bajt z portu, gdy zaś jest słowem (AX), jeden bajt pobrany będzie z portu "portnum" a drugi z "portnum"+1.
Warto tu jeszcze zaznaczyć, że "akumul" to bezwzględnie rejestr AL (port), lub AX (portw) - inne rejestry nie są dozwolone. W pascalu zapis instrukcji IN wyglądał więc by tak: var
al:byte;
ax:word;
...
al:=port[portnum];
lub
AX:=portw[portnum]; (w zależności od tego o czym pisałem).

OUT (out - poza) wyrzuca "akumul"(AL lub AX) na port - jest to robione analogicznie jak przy IN tzn. jeśli "akumul" jest bajtem, to wówczas bajt ten zostanie wrzucony na port o numerze "portnum", jeśli "akumul" jest słowem(AX) - AL pujdzie na port o numerze "portnum", AH natomiast na port "portnum"+1.
W pascalu wyglądać to będzie:
port[portnum]:=AL;
lub
portw[portnum]:=AX; Oczywiście tutaj również "akumul" znaczy wyłącznie rejestr AX (accumulator register - rejestr akumulatora).

Pewnych wyjaśnień wymaga tu jeszcze "portnum" - otóż nie powiedzieliśmy sobie, czy ma to być rejestr czy też wartość wpisywana bezpośrednio... i tu sprawa nie jest już tak prosta.

Zasada jest prosta - jeśli numer portu na który chcemy coś wyrzucić bądź pobrać jest <=0FFH (255) (wartość bajt), to wówczas możemy go adresować zarówno bezpośrednio (IN AL, 60H) jak i przez rejestr (IN AL, DX).
Gdy więc "portnum" jest >255 (dwubajtowy), wówczas możemy odwoływać się wyłącznie przez rejestr DX, w sposób następujący:
...; deklaracje segmentów itd.
MOV DX,378H; numer lpt1, przykładowy numer portu
OUT DX, AL ; wyrzucenie wartości AL na port 378h
...; dalsza część pprogramu
 

Jak już pisałem porty same w sobie bez znajomości sposobu odwoływania się do urządzeń nie dają nam zbyt wielkich możliwości; niestety - specyfikacje urządzeń bywają niekiedy znacznie trudniejsze od przerwań choćby dlatego, że nie ma żadnych generalnych ustaleń - każde urządzenie (dysk twardy, interfejs midi... czy wreszcie karta muzyczna) ma swój własny standard... o tym więc mówi się przy okazji omawiania "konieczności znajomości budowy wewnętrznej komputera" przed przystąpieniem do nauki Assemblera.

Pewne rzeczy jednak, należą do "klasyki" - np. to, że port 60H jest portem klawiatury i z niego można czytać znaki bezpośrednio: Jeśli wartość pobrana z tego portu jest <80h, to znaczy, że wciśnięto jakiś klawisz (wówczas wartość portu 60H = skankod tego klawisza), jeśli zaś AL będzie >80H - znaczy, że puszczono klawisz (wartość na porcie =skankod puszczonego klawisza +128).
Skankod jest zdecydowanie czymś innym niż Ascii - np. klawisz ESC ma tu wartość 01H... jeśli chcesz uzyskać listę skankodów zajrzyj do książki, lub napisz sobie prosty program (w assemblerze), który wyświetli kod naciskanego klawisza i poeksperymentuj.