0887 - MS-Dos - Od środka cz.3

Po wykonaniu zadania przez program, który nie jest już dłużej potrzebny, należy zwolnić zajmowaną przez niego pamięć i przekazać sterowanie z powrotem do systemu operacyjnego. Można to zrealizować różnymi metodami, np. umieszczając w końcowym fragmencie programu jedną z trzech sekwencji rozkazów :

Zakończenie wykonywania programu

 1) INT 20h
 2) MOV AH, 00h
    INT 21h
 3) MOV AH, 4Ch
    INT 21h

Odmianą pierwszej metody jest zakończenie w sposób następujący :

 4) długi skok pod adres początkowy PSP (znajduje się tam kod instrukcji INT 20h),

a odmianą metody drugiej i trzeciej jest zakończenie :

 5) nadanie odpowiedniej wartości rejestrowi AH i długi skok pod
    adres przesunięty względem początku PSP o 50h (znajdują się
    tam kody rozkazów INT 21h i RETF).

Najdogodniejsza jest trzecia metoda, gdyż nie wymaga spełnienia żadnych dodatkowych warunków. Funkcja 4Ch występuje jednak dopiero w wersji MS-DOS 2.0 i późniejszych. Pozostałe metody wymagają, aby rejestr segmentu kodu CS wskazywał na początek obszaru PSP. Czwarty sposób wprowadzono prawdopodobnie dla zmniejszenia skutków ewentualnych błędów, jeśli skonsolidowany program zawiera nie przypisane odwołania zewnętrzne, to w ich miejsce wstawiane jest 0. Skok pod taki adres spowoduje więc zakończenie programu.

Piąta metoda przewidziana została z myślą o przyszłych wersjach systemu operacyjnego, w których usługi systemowe będzie się realizowało nie za pomocą przerwań programowych, lecz przez wywołania procedur systemowych.

Usługi i funkcje systemowe

MS-DOS, jako system operacyjny, jest programem nadzorującym pracę komputera. Z drugiej strony można go traktować jako zestaw gotowych do wykorzystania w programach użytkowych procedur załadowanych do pamięci. Dostęp do nich, czyli usługi systemowe, można uzyskać na dwa sposoby : poprzez przerwania programowe (tylko niektóre usługi) lub poprzez wywołania funkcji systemowych (zalecane przez twórców systemu). System MS/PC-DOS od chwili powstania był poddawany wielu modyfikacjom. Jedne polegały na poprawie zauważonych drobnych błędów, inne na umożliwieniu współpracy z nowym sprzętem, jeszcze inne - na dodaniu nowych funkcji. Początkowo (w wersjach PC-DOS 1.00 i PC-DOS 1.10) funkcje systemowe były odpowiednikami funkcji oferowanych przez "stary" 8-bitowy system CP/M. Są one obecnie nazywane funkcjami uniwersalnymi, gdyż występują we wszystkich wersjach systemu (od 1.0 do 3.3). W wersji 2.0 wprowadzono funkcje realizujące usługi zbliżone do oferowanych w systemie UNIX (m.in. obsługujące hierarchiczny system plików). Nazywa się je funkcjami rozszerzonymi.

Wszystkie funkcje systemowe wywoływane są za pomocą przerwania programowego INT 21h. W rejestrze AH należy umieścić numer wybranej funkcji. W innych rejestrach mogą się znajdować parametry wejściowe - przy wywoływaniu funkcji i parametry wyjściowe - przy powrocie. Ponadto funkcje rozszerzone przy wyjściu przekazują w rejestrze AX kod błędu.

Funkcje uniwersalne można podzielić na następujące grupy logiczne :

  • 00h - funkcja nie związana z urządzeniem
  • 01h ... 0Ch - funkcje we-wy urządzeń znakowych
  • 0Dh ... 24h - funkcje zarządzające plikami
  • 25h ... 26h - dalsze funkcje nie związane z urządzeniami
  • 27h ... 29h - dalsze funkcję zarządzające plikami
  • 2Ah ... 2Eh - dalsze funkcje nie związane z urządzeniami.

Funkcje we-wy urządzeń znakowych

Umożliwiają one pobranie lub wysłanie znaku w ramach komunikacji z klawiaturą, ekranem, drukarką, wejściem i wyjściem szeregowym. Poniżej opisano te funkcje przy założeniu, że nie zmieniono przyporządkowania urządzeń rzeczywistych do urządzeń logicznych (CON:, PRN:, AUX:). Począwszy od wersji MS-DOS 2.0, można za pomocą polecenia MODE zmienić to przyporządkowanie.

  • Funkcja 01h (wejście z klawiatury z echem na ekranie) - czeka na wprowadzenie znaku z klawiatury i zwraca kod znaku w rejestrze AL, wysyłając jednocześnie ten znak na ekran.

Jeśli z klawiatury został odczytany znak ASCII (zwykły : kod 1 do 127 lub rozszerzony : kod 128 do 255), to własnie ten kod jest zwracany w AL. Jeśli jednak wystąpiła jedna z 97 specjalnych kombinacji (np. ALT A albo F1), to w rejestrze AL zwracana jest wartość 0. Należy wówczas powtórnie wywołać funkcję 01h, aby w rejestrze AL otrzymać kod reprezentujący tę kombinację (ang. pseudo-scan code).

Różne funkcje dotyczące klawiatury można klasyfikować na podstawie trzech kryteriów :

  • oczekiwania przez daną funkcję na znak;
  • wysyłania echa na ekran;
  • reakcji na naciśnięcie kombinacji klawiszy CTRL i BREAK (lub CTRL i C).

Funkcja 01h - spełnia wszystkie powyższe kryteria.

  • Funkcja 02h - (wyjście na ekran), wysyła znak z rejestru DL na ekran.
  • Funkcja 03h - (wyjście szeregowe), czeka na pojawienie się znaku w kanale szeregowym i umieszcza go w rejestrze AL. Normalnie kanałem szeregowym jest pierwszy port RS-232.
  • Funkcja 04h - (wyjście szeregowe), wysyła znak z rejestru DL do kanału szeregowego.
  • Funkcja 05h - (wyjście na drukarkę), wysyła znak z rejestru DL na urządzenie przyłączone do pierwszego portu interfejsu równoległego. Najczęściej jest to drukarka. Jeśli drukarka dołączona jest do interfejsu szeregowego, to bez wydania odpowiedniego polecenia MODE (zmieniające urządzenie docelowe) drukarka nie będzie obsługiwana.
  • Funkcja 06h - (bezpośrednie we-wy klawiatura/ekran), może być użyta do pobrania znaku albo do jego wysłania. Jeśli AL jest różne od FFh, to znak z AL jest wysyłany na ekran. Jeśli AL jest równe FFh, to następuje sprawdzenie klawiatury : w wypadku wciśnięcia klawisza znacznik zera (ZF) przy wyjściu z procedury jest równy 0, a w rejestrze AL znajduje się kod; w przeciwnym wypadku ZF ma wartość 1. Funkcja 06h nie czeka na wciśnięcie klawisza, nie wysyła echa na ekran, i nie reaguje na CTRL-BREAK.
  • Funkcja 07h - (bezpośrednie wejście z klawiatury bez echa na ekranie), działa podobnie jak funkcja 01h z tą różnicą, że nie wysyła echa na ekran, i nie reaguje na CTRL-BREAK.
  • Funkcja 08h - (wejście z klawiatury bez echa), działa podobnie jak funkcja 01h z tą różnicą, że nie wysyła echa na ekran. Od funkcji 07h różni się tylko tym, że reaguje na klawisze CTRL-BREAK.
  • Funkcja 09h - (wyświetlenie łańcucha znaków), wysyła na ekran łańcuch znaków. Położenie początku łańcucha w pamięci wskazują rejestry DS:DX. Łańcuch musi kończyć się znakiem dolara $, który nie jest wyświetlany.
  • Funkcja 0Ah - (buforowane wejście z klawiatury), pozwala na wprowadzanie znaków do bufora i ich edycję za pomocą klawiszy edytujących (BACKSPACE i DELETE), aż do chwili wciśnięcia klawisza RETURN (napotkania kodu 13h). Adres bufora przekazywany jest w rejestrach DS:DX. Pierwszy bajt w buforze musi być wpisany przez program przez wywołaniem funkcji i określać maksymalną liczbę wprowadzanych znaków. Drugi bajt jest zapisywany przez funkcję 0Ah i po wyjściu z niej określa faktyczną liczbę wprowadzonych znaków. Ostatni znak, odpowiadający klawiszowi RETURN (13h) jest umieszczany w buforze, ale nie wlicza się go do ogólnej liczby znaków. Jeśli przy wprowadzaniu znaków bufor zostanie zapełniony, to kolejne znaki będą ignorowane i rozlegać się będzie ostrzegawczy dźwięk z głośnika.
  • Funkcja 0Bh - (sprawdzenie stanu klawiatury), jeśli podany został znak z klawiatury rejestr AL = FFh jeżeli nie - AL = 0.
  • Funkcja 0Ch - (zerowanie bufora klawiatury i wywołanie funkcji), powoduje najpierw wyzerowanie bufora klawiatury w pamięci RAM (czyli skasowanie wszelkich wprowadzonych, ale nie odczytanych dotąd przez program znaków), a następnie - jeśli AL ma jedną z wartości: 01h, 06h, 07h, 08h, 0Ah - wykonanie funkcji obsługującej klawiaturę, zgodnie z numerem podanym w rejestrze AL. W szczególnym wypadku (gdy AL = 06h i DL = FFh), znak jest wysyłany na ekran, a nie wczytywany z klawiatury.

--- * --- * ---

 NAME TEST_DRUKARKI

 ; Program wyprowadza na drukarkę wiersze składające się
 ; ze znaków o kolejnych kodach ASCII
 ; pierwszy wiersz zaczyna się od spacji (20h), następny
 ; od wykrzyknika (21h), itd. Wyprowadzanie można przerwać
 ; przez wciśnięcie dowolnego klawisza

 STACK SEGMENT STACK
   DW  20  DUP(?)
 STACK ENDS

 CODE SEGMENT 'CODE'
 
   ASSUME  CS:CODE, DS:CODE, ES:NOTHING, SS:STACK

   ; kody znaków
   CR    :  EQU  0Dh   ; RETURN
   LF    :  EQU  0Ah   ; LINEFEED
   SPACE :  EQU  20h   ; SPACJA

   ; przerwanie dla wywołań funkcyjnych DOS
   DOS :  EQU 21h

   ; numery wywołań funkcyjnych DOS
   OUT_STRUNG      :  EQU  09h  ; wyświetlenie łańcucha znaków
   PRINT_CHARACTER :  EQU  05h  ; wydrukowanie znaku
   KEY_STATUS      :  EQU  0Bh  ; sprawdzenie klawiatury
   RESET_KEY       :  EQU  0Ch  ; wyczyszczenie klawiatury
   TERMINATE       :  EQU  4Ch  ; zakończenie programu

   ; teksty
   START_TEXT  DB  'rozpoczecie testowania drukarki ...',CR,LF,LF,'$'
   END_TEXT    DB  'testowanie drukarki przerwane',CR,LF,LF,'$'

   START:
     MOV   AX, CS
     MOV   DS, AX                 ; segment danych ma się pokrywać z seg. kodu
     MOV   AH, RESET_KEY          ; opróżnienie bufora klawiatury
     MOV   AL, FFh
     INT   DOS
     MOV   DX, OFFSET START_TEXT  ; ustalenie adresu komunikatu
     MOV   AH, OUT_STRING         ; wyświetlenie komunikatu
     INT   DOS

   INIT:
     MOV   BL, SPACE

   AGAIN:
     MOV   DL, BL                 ; pierwszy znak do wysłania w wierszu
     MOV   CX, 80                 ; licznik znaków w wierszu
     MOV   AH, PRINT_CHARACTER    ; funkcja 05h - wydrukowanie znaku

   LOOP:
     INT   DOS
     INC   DL                     ; następny znak
     CMP   DL, 7Fh
     JNZ   DALEJ                  ; następny znak <> 7Fh
     MOV   DL, SPACE              ; pominięcie znaków 00h - 1Fh
     OR    DL, DL                 ; kasowanie wskaźnika zera

   DALEJ:
     LOOPNZ LOOP                  ; CX <- CX-1, skok jeśli CX<>0
     MOV   DL, CR                 ; wyprowadzenie RETURN
     INT   DOS
     MOV   DL, LF                 ; wyprowadzenie LINEFEED
     INT   DOS
     MOV   AH, KEY_STATUS         ; sprawdzenie klawiatury
     INT   DOS
     OR    AL, AL                 ; wciśnięto klawisz
     JZ    PRINT                  ; nie, następny wiersz
     MOV   DX, OFFSET END_TEXT    ; adres komunikatu
     MOV   AH, OUT_STRING         ; wyświetlenie komunikatu
     INT   DOS
     MOV   TERMINATE
     INT   DOS                    ; zakończenie programu

   PRINT:
     INC   BL                     ; pierwszy znak następnego wiersza
     CMP   BL, 7Fh
     JNZ   AGAIN                  ; jeśli nie 7Fh, drukuj wiersz od tego znaku
     JMP   INIT                   ; jeśli 7Fh, drukuj wiersz od spacji
 
 CODE ENDS
 END START

Na wydruku przedstawiono prosty, lecz jednocześnie użyteczny program testujący drukarkę. Wykorzystano w nim funkcje uniwersalne 05h, 09h, 0Bh, 0Ch. Zakończenie programu odbywa się przez wykorzystanie funkcji rozszerzonej 4Ch. Jeśli przedstawiony tu tekst źródłowy zostanie zapamiętany w pliku testdruk.asm, to w celu uzyskania skompilowanego i skonsolidowanego programu oraz jego wykonania należy uzyć programów masm.exe i link.exe, wprowadzając następujące polecenia : masm testdruk link testdruk testdruk.

opr. Zbigniew Pojmański wg mc 12/85
Mikroklan - Wrzesień 1987r.