BLOK 1: Podstawy I/O i operacje na danych#
Informacje organizacyjne#
Termin oddania: do 12.12.2025
Punktacja: 7 punktów
Opóźnienie: -3 punkty za każdy tydzień
1. Środowisko pracy#
Kompilacja w DOSBox-X#
D:\> cd project
D:\PROJECT> cl programSkrypt cl automatycznie wykonuje:
tasm program.asm- kompilacja do .OBJtlink program.obj- linkowanie do .EXE- Wyświetla ewentualne błędy
Debugowanie - TurboDebugger#
D:\PROJECT> td program.exePodstawowe komendy:
F7- Step Into (krok do instrukcji)F8- Step Over (pomiń CALL)F9- Run to cursorCtrl+F2- Reset programuAlt+V- View menu (rejestry, pamięć, stos)
Porównanie z Visual Studio#
Na zajęciach pokażę jak ten sam kod C wygląda w asemblerze pod Windows (x64).
To pomoże zrozumieć koncepcje uniwersalne dla każdej architektury.
2. Instrukcje asemblera - podstawy#
2.1. Struktura programu .EXE#
Każdy program w asemblerze dla DOS musi mieć określoną strukturę:
.model small ; Model pamięci
.stack 512 ; Rozmiar stosu
.data
; Tutaj deklarujemy zmienne
.code
main proc
; Inicjalizacja segmentu danych
mov ax, @data
mov ds, ax
; Właściwy kod programu
; Zakończenie programu
mov ax, 4C00h
int 21h
main endp
end mainWyjaśnienie:
.model small- określa, że kod i dane mieszczą się w 64KB każdy.stack 512- rezerwuje 512 bajtów na stos.data- sekcja dla zmiennych zainicjalizowanych.code- sekcja z instrukcjami programu@data- adres segmentu danych (generowany przez assembler)mov ax, 4C00h; int 21h- standardowe zakończenie programu DOS
2.2. Rejestry procesora - przypomnienie#
Procesor 8086 ma następujące rejestry 16-bitowe, z których każdy można podzielić na dwie części 8-bitowe:
| Rejestr | Części 8-bit | Typowe użycie |
|---|---|---|
| AX | AH, AL | Akumulator - arytmetyka, I/O, funkcje DOS |
| BX | BH, BL | Baza - adresowanie pamięci |
| CX | CH, CL | Licznik - pętle, przesunięcia |
| DX | DH, DL | Dane - I/O, mnożenie/dzielenie |
Rejestry wskaźnikowe:
- SI - Source Index (indeks źródłowy)
- DI - Destination Index (indeks docelowy)
- BP - Base Pointer (wskaźnik bazy stosu)
- SP - Stack Pointer (wskaźnik stosu)
Rejestry segmentowe:
- CS - Code Segment (segment kodu)
- DS - Data Segment (segment danych)
- SS - Stack Segment (segment stosu)
- ES - Extra Segment (dodatkowy segment)
2.3. Przerwania DOS (INT 21h)#
INT 21h to główne przerwanie DOS-u do obsługi wejścia/wyjścia.
Najważniejsze funkcje dla BLOKU 1:#
| Funkcja (AH) | Opis | Parametry wejściowe | Wynik |
|---|---|---|---|
| 01h | Czytaj znak z echo | - | AL = znak |
| 02h | Wypisz znak | DL = znak | - |
| 09h | Wypisz string | DS:DX = adres (kończy $) | - |
Przykład użycia funkcji 02h:
mov ah, 02h ; Funkcja 02h - wypisz znak
mov dl, 'A' ; Znak do wyświetlenia
int 21h ; Wywołaj DOSPrzykład użycia funkcji 01h:
mov ah, 01h ; Funkcja 01h - czytaj znak
int 21h ; Wywołaj DOS
; Teraz AL zawiera wczytany znakPrzykład użycia funkcji 09h:
.data
tekst db 'Hello World!$' ; String musi kończyć się $
.code
lea dx, tekst ; DX = adres stringa
mov ah, 09h ; Funkcja 09h
int 21h ; Wyświetl string2.4. Podstawowe operacje arytmetyczne#
; Dodawanie
mov al, 5
add al, 3 ; AL = 8
; Odejmowanie
mov al, 10
sub al, 4 ; AL = 6
; Inkrementacja / Dekrementacja
mov cx, 5
inc cx ; CX = 6
dec cx ; CX = 52.5. Porównania i skoki warunkowe#
; Porównanie
cmp al, 5 ; Porównuje AL z 5 (AL - 5)
je rowne ; Jump if Equal (jeśli AL = 5)
jne nierowne ; Jump if Not Equal (jeśli AL ≠ 5)
jg wieksze ; Jump if Greater (jeśli AL > 5, signed)
jl mniejsze ; Jump if Less (jeśli AL < 5, signed)2.6. Pętle#
mov cx, 10 ; Licznik
petla:
; Kod do powtórzenia
loop petla ; CX--, jeśli CX ≠ 0 skocz do 'petla'2.7. Konwersja cyfr ASCII#
Bardzo ważne dla zadań:
Gdy wczytujemy cyfrę z klawiatury (funkcja 01h), dostajemy jej kod ASCII, nie wartość liczbową!
| Cyfra | Kod ASCII (hex) | Kod ASCII (dec) |
|---|---|---|
| ‘0’ | 30h | 48 |
| ‘1’ | 31h | 49 |
| ‘2’ | 32h | 50 |
| … | … | … |
| ‘9’ | 39h | 57 |
Konwersja cyfra ASCII → wartość liczbowa:
mov ah, 01h ; Wczytaj cyfrę
int 21h ; AL = '5' = 35h
sub al, '0' ; AL = 5 = 05h (wartość liczbowa)
; lub równoważnie:
sub al, 30hKonwersja wartość liczbowa → cyfra ASCII:
mov al, 5 ; Wartość liczbowa
add al, '0' ; AL = '5' = 35h (kod ASCII)
; lub równoważnie:
add al, 30hKonwersja małe/wielkie litery:
| Litera | Kod ASCII (hex) | Różnica |
|---|---|---|
| ‘A’ | 41h | - |
| ‘a’ | 61h | 20h |
| ‘Z’ | 5Ah | - |
| ‘z’ | 7Ah | 20h |
; Wielka → mała
mov al, 'A' ; AL = 41h
add al, 20h ; AL = 61h = 'a'
; lub:
or al, 20h ; Ustaw bit 5
; Mała → wielka
mov al, 'a' ; AL = 61h
sub al, 20h ; AL = 41h = 'A'
; lub:
and al, 0DFh ; Wyzeruj bit 53. Przykłady: C vs Asembler#
Przykład 1: Hello World#
Kod C:
#include <stdio.h>
int main() {
printf("Hello World!\n");
return 0;
}Asembler x86-16 (TASM):
.model small
.stack 256
.data
tekst db 'Hello World!', 0Dh, 0Ah, '$'
; 0Dh = Carriage Return, 0Ah = Line Feed, '$' = koniec
.code
main proc
mov ax, @data
mov ds, ax
; Wyświetl string
lea dx, tekst ; DX = adres stringa
mov ah, 09h ; Funkcja 09h - wypisz string
int 21h ; Wywołaj DOS
; Zakończ program
mov ax, 4C00h
int 21h
main endp
end mainVisual Studio (x64 - do demonstracji):
; Visual Studio - Disassembly view
lea rcx, [format_string] ; Pierwszy parametr (64-bit)
call printf ; Wywołanie funkcji CAnaliza różnic:
- DOS: Używamy przerwania INT 21h do komunikacji z systemem
- x64: Używamy wywołań funkcji biblioteki C (printf)
- DOS: String kończy się znakiem ‘$’
- C: String kończy się znakiem ‘\0’ (null terminator)
- DOS: Bezpośrednia komunikacja ze sprzętem przez BIOS/DOS
- Modern: Abstrakcja przez system operacyjny
Przykład 2: Wczytanie i wyświetlenie znaku#
Kod C:
#include <stdio.h>
int main() {
char znak;
printf("Wpisz znak: ");
scanf("%c", &znak);
printf("Wpisales: %c\n", znak);
return 0;
}Asembler (TASM):
.model small
.stack 256
.data
prompt db 'Wpisz znak: $'
wynik db 0Dh, 0Ah, 'Wpisales: $'
.code
main proc
mov ax, @data
mov ds, ax
; Wyświetl prompt
lea dx, prompt
mov ah, 09h
int 21h
; Wczytaj znak
mov ah, 01h ; Funkcja 01h - czytaj znak z echo
int 21h ; AL = wczytany znak
mov bl, al ; Zapisz znak w BL
; Wyświetl komunikat
lea dx, wynik
mov ah, 09h
int 21h
; Wyświetl znak
mov dl, bl ; Znak do wyświetlenia
mov ah, 02h ; Funkcja 02h - wypisz znak
int 21h
mov ax, 4C00h
int 21h
main endp
end mainAnaliza:
- W C używamy funkcji
scanfiprintf- wysokopoziomowa abstrakcja - W asemblerze bezpośrednio wywołujemy funkcje DOS przez INT 21h
- Musimy ręcznie zarządzać rejestrami (AL, BL, DL)
- Każda operacja I/O wymaga ustawienia odpowiedniej funkcji w AH
Przykład 3: Prosta arytmetyka#
Kod C:
#include <stdio.h>
int main() {
int a = 5;
int b = 3;
int suma = a + b;
printf("Suma: %d\n", suma);
return 0;
}Asembler (TASM) - wersja uproszczona:
.model small
.stack 256
.data
a db 5
b db 3
suma db 0
.code
main proc
mov ax, @data
mov ds, ax
; Oblicz sumę
mov al, a ; AL = 5
add al, b ; AL = AL + 3 = 8
mov suma, al ; Zapisz wynik
; Wyświetl wynik (zakładając jednocyfrowy)
add al, '0' ; Konwersja na ASCII
mov dl, al
mov ah, 02h
int 21h
mov ax, 4C00h
int 21h
main endp
end mainAnaliza:
- C: Kompilator automatycznie przydziela zmienne
- Asembler: Musimy jawnie zadeklarować zmienne w sekcji .data
- C: Operacje arytmetyczne są abstrakcyjne
- Asembler: Bezpośrednie operacje na rejestrach procesora
- C: printf obsługuje formatowanie
- Asembler: Ręczna konwersja liczby na znak ASCII
Przykład 4: Pętla i wyświetlanie#
Kod C:
#include <stdio.h>
int main() {
for (int i = 0; i < 10; i++) {
printf("*");
}
printf("\n");
return 0;
}Asembler (TASM):
.model small
.stack 256
.code
main proc
mov ax, @data
mov ds, ax
mov cx, 10 ; Licznik pętli
petla:
mov dl, '*' ; Znak do wyświetlenia
mov ah, 02h ; Funkcja 02h
int 21h
loop petla ; CX--, jeśli CX ≠ 0 goto petla
; Nowa linia
mov dl, 0Dh ; Carriage Return
mov ah, 02h
int 21h
mov dl, 0Ah ; Line Feed
mov ah, 02h
int 21h
mov ax, 4C00h
int 21h
main endp
end mainAnaliza:
- C: Pętla
forz jawnym licznikiem i warunkiem - Asembler: Instrukcja
LOOPużywa rejestru CX - Procesor automatycznie dekrementuje CX i sprawdza warunek
- W C nowa linia to
\n, w DOS to dwa znaki: CR (0Dh) + LF (0Ah)
4. Zadania do wykonania#
Forma oddawania#
Każde zadanie oddajemy jako:
- Kod źródłowy (.asm)
- Skompilowany program (.exe)
- Sprawozdanie (PDF lub MD) zawierające:
- Opis rozwiązania
- Wyjaśnienie kluczowych fragmentów kodu
- Zrzuty ekranu z działania programu
- Napotkane problemy i ich rozwiązania
Zadanie 1: Hello World#
Treść zadania: Napisz program, który wyświetla na ekranie Twoje imię i nazwisko, a następnie kończy działanie.
Wymagania:
- Użyj funkcji DOS 09h (wyświetlanie stringa)
- String musi kończyć się znakiem ‘$’
- Program musi poprawnie zakończyć działanie (INT 21h, AH=4Ch)
Wskazówki:
.data
tekst db 'Twoje Imie Nazwisko$'W sprawozdaniu opisz:
- Dlaczego string musi kończyć się znakiem ‘$’?
- Jaka jest rola instrukcji
lea dx, tekst? - Co oznacza kod
mov ax, 4C00h; int 21h?
Zadanie 2: Wczytaj i wyświetl znak#
Treść zadania:
Napisz program, który w pętli wczytuje znaki z klawiatury i wyświetla je na ekranie.
Program ma pomijać wszystkie znaki oprócz cyfr (‘0’-‘9’).
Pętla kończy się po naciśnięciu klawisza ESC (kod 1Bh).
Wymagania:
- Użyj funkcji 01h (wczytaj znak z echo) lub 08h (bez echo)
- Sprawdź czy znak jest cyfrą (zakres ‘0’-‘9’)
- Jeśli tak - wyświetl go funkcją 02h
- Jeśli nie - pomiń i czytaj następny
- Zakończ po naciśnięciu ESC
Wskazówki:
; Sprawdzenie czy cyfra:
cmp al, '0' ; Czy >= '0'?
jb nie_cyfra ; Jump if Below (mniejsze)
cmp al, '9' ; Czy <= '9'?
ja nie_cyfra ; Jump if Above (większe)
; Tutaj jest cyfraW sprawozdaniu wyjaśnij:
- Jaka jest różnica między funkcją 01h a 08h?
- Dlaczego używamy instrukcji
jbijazamiastjlijg? - Jaki kod ASCII ma klawisz ESC i dlaczego taki?
Zadanie 3: Suma dwóch liczb jednocyfrowych#
Treść zadania: Napisz program, który:
- Wczytuje dwie cyfry z klawiatury (znaki ‘0’-‘9’)
- Oblicza ich sumę jako wartości liczbowe
- Wyświetla wynik jako literę (od A do R)
Przykład:
- Wejście: ‘3’ i ‘5’
- Suma wartości: 3 + 5 = 8
- Wynik: ‘H’ (ósma litera alfabetu)
Wymagania:
- Konwersja cyfr ASCII na wartości liczbowe
- Dodawanie wartości
- Konwersja wyniku na literę (0→‘A’, 1→‘B’, …, 8→‘I’)
- Zakładamy, że suma < 18 (wynik < ‘S’)
Wskazówki:
; Konwersja cyfra ASCII → wartość:
sub al, '0' ; lub sub al, 30h
; Konwersja liczba → litera:
add al, 'A' ; lub add al, 41hW sprawozdaniu wyjaśnij:
- Dlaczego odejmujemy 30h od cyfry ASCII?
- Jaki kod ASCII ma litera ‘A’ i dlaczego to ważne?
- Co się stanie jeśli suma będzie >= 26? (opcjonalnie: jak obsłużyć?)
Zadanie 4: Konwersja małe/wielkie litery#
Treść zadania: Napisz program, który:
- Wczytuje jeden znak z klawiatury
- Sprawdza czy to litera (mała lub wielka)
- Jeśli mała litera → zamienia na wielką
- Jeśli wielka litera → zamienia na małą
- Wyświetla przekonwertowany znak
Wymagania:
- Sprawdzenie zakresu ‘a’-‘z’ i ‘A’-‘Z’
- Konwersja przez dodanie/odjęcie 20h
- Wyświetlenie wyniku
Wskazówki:
; Sprawdzenie czy wielka litera:
cmp al, 'A'
jb nie_wielka
cmp al, 'Z'
ja nie_wielka
; Tutaj jest wielka litera
; Konwersja wielka → mała:
add al, 20h ; lub or al, 20h
; Konwersja mała → wielka:
sub al, 20h ; lub and al, 0DFhW sprawozdaniu wyjaśnij:
- Dlaczego różnica między małą a wielką literą to dokładnie 20h?
- Jaki bit jest odpowiedzialny za wielkość litery?
- Dlaczego
or al, 20hzamienia na małą, aand al, 0DFhna wielką? - Co program powinien zrobić jeśli wejście nie jest literą?
Zadanie 5: Wyświetlanie ciągu znaków w pętli#
Treść zadania:
Napisz program, który wyświetla 10 razy znak ‘*’ w jednej linii,
używając pętli z rejestrem CX.
Wymagania:
- Użycie instrukcji LOOP
- Rejestr CX jako licznik
- Funkcja 02h do wyświetlania pojedynczego znaku
Wskazówki:
mov cx, 10 ; Licznik
petla:
mov dl, '*'
mov ah, 02h
int 21h
loop petla ; CX--, if CX ≠ 0 goto petlaW sprawozdaniu wyjaśnij:
- Jak działa instrukcja LOOP krok po kroku?
- Co się stanie jeśli CX będzie miało wartość 0 przed pętlą?
- Dlaczego używamy CX, a nie innego rejestru?
- Jak wyświetlić 100 razy znak ‘*’ używając tylko 16-bitowego CX?
5. Wskazówki ogólne#
Dobre praktyki#
Zawsze inicjalizuj segment danych
mov ax, @data mov ds, axZawsze poprawnie kończ program
mov ax, 4C00h ; Kod zakończenia 0 w AL int 21hUżywaj znaczących nazw etykiet
; DOBRZE: wczytaj_znak: koniec_petli: ; ŹŹLE: etykieta1: x:Dodawaj komentarze
mov ah, 01h ; Funkcja 01h - czytaj znak int 21h ; Wywołaj DOS, wynik w AL
Częste błędy#
Zapomnienie o inicjalizacji DS
; ŹŹLE: .code main proc lea dx, tekst ; DS nie wskazuje na @data! ; DOBRZE: .code main proc mov ax, @data mov ds, ax lea dx, tekstBrak znaku ‘$’ w stringu
; ŹŹLE: tekst db 'Hello' ; Funkcja 09h nie wie gdzie koniec! ; DOBRZE: tekst db 'Hello$'Niepoprawne zakończenie programu
; ŹŹLE: ret ; To nie jest DOS! ; DOBRZE: mov ax, 4C00h int 21hMylenie kodów ASCII z wartościami
; ŹŹLE: mov ah, 01h int 21h ; AL = '5' = 35h add al, 3 ; AL = 38h = '8' (NIEPOPRAWNE!) ; DOBRZE: mov ah, 01h int 21h ; AL = '5' = 35h sub al, '0' ; AL = 5 (wartość liczbowa) add al, 3 ; AL = 8 add al, '0' ; AL = '8' = 38h (ASCII)Zapomnienie o destrukcyjnym charakterze instrukcji
; ŹŹLE: mov al, znak1 add al, znak2 ; AL zawiera sumę mov dl, al ; ...ale AL już straciliśmy znak1! ; DOBRZE: mov al, znak1 mov bl, al ; Kopia na później add al, znak2
Przydatne kody ASCII#
| Znak | Hex | Dec | Znaczenie |
|---|---|---|---|
| NUL | 00h | 0 | Null terminator (C) |
| BEL | 07h | 7 | Dzwonek |
| BS | 08h | 8 | Backspace |
| TAB | 09h | 9 | Tabulacja |
| LF | 0Ah | 10 | Line Feed (nowa linia) |
| CR | 0Dh | 13 | Carriage Return |
| ESC | 1Bh | 27 | Escape |
| SPACE | 20h | 32 | Spacja |
| ‘0’ | 30h | 48 | Cyfra zero |
| ‘9’ | 39h | 57 | Cyfra dziewięć |
| ‘A’ | 41h | 65 | Wielka litera A |
| ‘Z’ | 5Ah | 90 | Wielka litera Z |
| ‘a’ | 61h | 97 | Mała litera a |
| ‘z’ | 7Ah | 122 | Mała litera z |
Debugowanie w TurboDebugger#
Co warto sprawdzić:
View → Registers - obserwuj zmiany rejestrów
- Czy AL zawiera poprawny kod ASCII?
- Czy CX się prawidłowo zmniejsza w pętli?
View → Dump - pamięć programu
- Czy twoje stringi są poprawnie zakończone ‘$’?
- Jak wyglądają dane w pamięci?
F7 (Step Into) - wykonuj program instrukcja po instrukcji
- Śledź jak zmieniają się rejestry
- Sprawdź czy skoki warunkowe działają jak należy
Breakpointy (F2) - zatrzymaj program w konkretnym miejscu
- Postaw breakpoint przed i po krytycznej operacji
- Sprawdź stan rejestrów
6. Kryteria oceny#
Każde zadanie oceniane jest według:
| Kryterium | Punkty |
|---|---|
| Program działa poprawnie | 40% |
| Kod jest czytelny i skomentowany | 20% |
| Sprawozdanie - wyjaśnienia techniczne | 25% |
| Jakość dokumentacji | 15% |
Uwaga: Nawet jeśli program nie działa w 100%, możesz otrzymać punkty za:
- Prawidłowe podejście do problemu
- Poprawną strukturę programu
- Merytoryczne wyjaśnienia w sprawozdaniu
- Próby rozwiązania i dokumentację problemów
Liczy się proces uczenia się i zrozumienie architektury!
Co powinno być w sprawozdaniu:#
- Opis problemu - co program ma robić
- Analiza techniczna:
- Jakie funkcje DOS użyłeś i dlaczego?
- Jakie rejestry są wykorzystywane?
- Jak działają kluczowe fragmenty kodu?
- Fragmenty kodu z komentarzami - najważniejsze sekcje
- Zrzuty ekranu - działający program
- Napotkane problemy - błędy i ich rozwiązania
- Wnioski - co się nauczyłeś?
7. Podsumowanie: Co powinniśmy wynieść z BLOKU 1#
Po tym bloku powinieneś rozumieć:
Strukturę programu w asemblerze
- Dyrektywy .model, .stack, .data, .code
- Procedura główna main proc…endp
- Inicjalizacja segmentu danych
- Zakończenie programu
Podstawy komunikacji z systemem DOS
- Przerwanie INT 21h i jego funkcje
- Funkcja 01h - wczytaj znak
- Funkcja 02h - wypisz znak
- Funkcja 09h - wypisz string
- Funkcja 4Ch - zakończ program
Rejestry procesora i ich role
- AX jako akumulator
- DX do przekazywania adresów i znaków
- CX jako licznik pętli
- Różnica między częściami 8-bit (AH, AL) a całym 16-bit (AX)
Kody ASCII i konwersje
- Różnica między kodem ASCII a wartością liczbową
- Konwersja cyfra ASCII ↔ wartość (±30h)
- Konwersja małe ↔ wielkie litery (±20h)
- Znaczenie bitów w reprezentacji znaków
Podstawowe konstrukcje programistyczne
- Pętle z instrukcją LOOP
- Porównania z CMP
- Skoki warunkowe (JE, JNE, JB, JA)
- Proste operacje arytmetyczne (ADD, SUB, INC, DEC)
Myślenie “blisko sprzętu”
- Każda operacja to bezpośrednia instrukcja procesora
- Ręczne zarządzanie rejestrami
- Brak automatycznych konwersji typów
- Kontrola nad każdym bajtem i bitem
Pamiętaj: To nie jest tylko nauka składni - to zrozumienie jak komputer rzeczywiście działa!
Po opanowaniu BLOKU 1 będziesz gotowy na bardziej zaawansowane tematy:
- Tablice i łańcuchy (BLOK 2)
- Procedury i funkcje (BLOK 3)
- Operacje na plikach (BLOK 4)
8. Zasoby dodatkowe#
Kody ASCII - kompletna tabela#
Dec Hex Znak | Dec Hex Znak | Dec Hex Znak | Dec Hex Znak
0 00h NUL | 32 20h SPC | 64 40h @ | 96 60h `
7 07h BEL | 33 21h ! | 65 41h A | 97 61h a
8 08h BS | 34 22h " | 66 42h B | 98 62h b
9 09h TAB | 35 23h # | 67 43h C | 99 63h c
10 0Ah LF | 36 24h $ | 68 44h D | 100 64h d
13 0Dh CR | 37 25h % | 69 45h E | 101 65h e
27 1Bh ESC | 48 30h 0 | 70 46h F | 102 66h f
| 49 31h 1 | 71 47h G | 103 67h g
| 50 32h 2 | 72 48h H | 104 68h h
| 57 39h 9 | 90 5Ah Z | 122 7Ah zPrzydatne wzory#
Sprawdzenie czy cyfra:
cmp al, '0'
jb nie_cyfra
cmp al, '9'
ja nie_cyfra
; tutaj jest cyfraSprawdzenie czy wielka litera:
cmp al, 'A'
jb nie_wielka
cmp al, 'Z'
ja nie_wielka
; tutaj jest wielka literaSprawdzenie czy mała litera:
cmp al, 'a'
jb nie_mala
cmp al, 'z'
ja nie_mala
; tutaj jest mała literaPowodzenia!
Marcin Klimek
Architektura i Organizacja Systemów Komputerowych
WSB Nowy Sącz, 2025/2026