Bölüm 5: emu8086.inc Kütüphanesi
Giriş
Öğrenme Çıktıları
Bir kütüphane dosyasını kaynağa eklemeyi ve derleyicinin dosyayı nerede aradığını açıklamak.
PUTC, GOTOXY, PRINT, PRINTN gibi makroların neye genişlediğini göstermek.
DEFINE_… ve CALL ile hazır prosedürleri (sayı okuma/yazma, dizge yazdırma) kullanmak.
Yığın üzerinden dönüş adresinin nasıl saklandığını izlemek; makro ile prosedürü boyut ve hız açısından karşılaştırmak.
Kütüphane ve INCLUDE
Ortak Fonksiyonlar Kütüphanesi
- Programlamayı kolaylaştırmak için sık kullanılan bazı işlevler hazır olarak bulunur.
- Başka dosyalarda tanımlanan işlevler INCLUDE direktifi ile kullanılır.
emu8086.inciçindeki herhangi bir işlevi kullanmak için kaynak dosyanın başınainclude 'emu8086.inc'yazılır.- Bu kütüphane, emu8086 platformunda sık kullanılan ekran, klavye ve sayı işlevlerini içerir.
INCLUDE bir direktiftir: işlemci komutu üretmez, derleme sırasında metin ekler.
Kütüphane ve INCLUDE
Kütüphanede Neler Var?
| Makro | Görev |
|---|---|
PUTC char | tek karakter yaz |
GOTOXY col, row | imleci konumlandır |
PRINT string | dizge yaz |
PRINTN string | dizge yaz + yeni satır |
CURSOROFF | imleci gizle |
CURSORON | imleci göster |
| Prosedür | Görev |
|---|---|
PRINT_STRING | DS:SI'deki dizgeyi yaz |
PTHIS | CALL'dan sonraki dizgeyi yaz |
GET_STRING | klavyeden dizge oku |
CLEAR_SCREEN | ekranı temizle |
SCAN_NUM | sayı oku → CX |
PRINT_NUM | AX'i işaretli yaz |
PRINT_NUM_UNS | AX'i işaretsiz yaz |
CALL ile çağrılır.Makrolar
Ekran Makroları
| Makro | Ne yapar? | Arka planda |
|---|---|---|
PUTC char | Geçerli imleç konumuna bir ASCII karakter yazar. | INT 10h, AH = 0Eh |
GOTOXY col, row | İmleci verilen sütun ve satıra konumlandırır. | INT 10h, AH = 02h |
PRINT string | Verilen dizgeyi yazar. | 0Eh ile karakter karakter |
PRINTN string | PRINT ile aynı; sonuna CR + LF (13, 10) ekleyerek yeni satıra geçer. | 0Eh ile karakter karakter |
CURSOROFF | Metin imlecini kapatır (gizler). | INT 10h, AH = 01h |
CURSORON | Metin imlecini açar. | INT 10h, AH = 01h |
PUTC 65, PUTC 'B', PUTC AL.Makrolar
PUTC ve GOTOXY Neye Genişler?
PUTC 'A'
PUSH AX ; AX'i koru MOV AL, 'A' ; parametre MOV AH, 0Eh ; teletype INT 10h POP AX ; AX geri
5 komut, 8 bayt. Yazmaçlar korunur; çağıran kod etkilenmez.
GOTOXY 10, 5
PUSH AX PUSH BX PUSH DX MOV AH, 02h ; imleç konumla MOV DH, 5 ; satır (row) MOV DL, 10 ; sütun (col) MOV BH, 0 ; sayfa 0 INT 10h POP DX POP BX POP AX
Makrolar
PRINT Neye Genişler?
PUSH AX PUSH SI JMP skip_dcl ; veriyi atla s_dcl DB 'Hello World!', 0 skip_dcl: LEA SI, s_dcl next_char: MOV AL, CS:[SI] ; karakteri al CMP AL, 0 JZ printed ; 0 → bitti INC SI MOV AH, 0Eh INT 10h JMP next_char printed: POP SI POP AX
- Dizge, makronun açıldığı yere, kodun içine gömülür;
JMPile üzerinden atlanır. - Sonuna 0 eklenir (null ile sonlanan dizge).
- Etiketler
LOCALtanımlıdır: makro her açılışta yeni adlar alır, çakışma olmaz. - Veri kod kesiminde olduğu için
CS:[SI]kesim öneki kullanılır. - PRINTN'de dizge
DB sdat, 13, 10, 0olarak tanımlanır.
Makrolar · Kodu adım adım çalıştır
Kod İzleme: PRINT, GOTOXY, PUTC
include: makro tanımları derleme sırasında eklenir; kod üretilmez.
ORG 100h: COM programı 100h'den başlar.
PRINT: 12 karakter (0–11. sütun) yazılır; imleç 12. sütunda.
GOTOXY 10, 5: imleç 10. sütun, 5. satıra taşınır. Ekrana bir şey yazılmaz.
PUTC 65: 65 = 41h = 'A' yazılır, imleç 11. sütuna geçer.
PUTC 'B': karakter sabiti doğrudan verilebilir.
RET: DOS'a dönüş. END yalnızca derleyiciye “kaynak bitti” der.
include emu8086.inc ORG 100h PRINT 'Hello World!' GOTOXY 10, 5 PUTC 65 ; 65 - is an ASCII code for 'A' PUTC 'B' RET ; return to operating system. END ; directive to stop the compiler.
Makrolar
PRINTN ve İmleç Makroları
PRINT 'a' ardından PRINT 'b' → ab aynı satırda.
PRINTN 'a' ardından PRINT 'b' → a ve alt satırda b.
CR (13) imleci satır başına, LF (10) bir alt satıra götürür; yeni satır için ikisi birden gerekir.
İmleç şeklini ayarlayan INT 10h, AH = 01h kullanılır: CH = başlangıç, CL = bitiş tarama satırı.
CH'nin 5. biti 1 yapılınca imleç gizlenir; CURSORON normal şekli geri yükler.
Oyun veya menü ekranlarında yanıp sönen imleci saklamak için kullanılır.
PRINTN 'Ad Soyad:' ; yazıp alt satıra geç CURSOROFF GOTOXY 30, 12 PRINT 'Merhaba' CURSORON
Makrolar
Demo: GOTOXY Ekranı
80 × 25 metin ekranında bir hücreye tıklayın: imleci oraya götüren makro, BIOS yazmaçları ve video belleğindeki karşılığı gösterilir.
Prosedürler
Prosedür Kullanımı: DEFINE_ ve CALL
include 'emu8086.inc' ORG 100h ... CALL print_num ; kullan ... RET DEFINE_PRINT_NUM ; tanımla DEFINE_PRINT_NUM_UNS END
- Her prosedür,
ENDdirektifinden önce kendiDEFINE_…makrosuyla bir kez tanımlanmalıdır. DEFINE_…makrosu, prosedürün kodunu bulunduğu yere açar.- Tanımlar genellikle
RET'ten sonra konur: aksi hâlde işlemci akış içinde prosedür koduna girer. - Kodda prosedür adıyla
CALLyapılır; adlar küçük harfle yazılır (print_num). PRINT_NUM, işini yaparkenPRINT_NUM_UNS'yi çağırır; ikisi birlikte tanımlanmalıdır.
Prosedürler
Dizge Prosedürleri
- Null (0) ile sonlanan dizgeyi geçerli imleç konumuna yazar.
- Dizgenin adresi DS:SI'den alınır.
- Tanım:
DEFINE_PRINT_STRING.
LEA SI, msg CALL print_string msg DB 'Merhaba', 0
- Null ile sonlanan dizgeyi yazar.
- Dizgenin adresini yığından alır: dizge,
CALL'dan hemen sonra tanımlanır. - Tanım:
DEFINE_PTHIS.
CALL pthis DB 'Merhaba', 0 ; buradan devam eder
Prosedürler
GET_STRING ve CLEAR_SCREEN
- Kullanıcıdan null ile sonlanan bir dizge alır.
- Dizge DS:DI'deki tampona (buffer) yazılır.
- DX = tampon boyutu; sona 0 eklendiği için en fazla DX − 1 karakter alınır.
- Enter tuşuna basılınca giriş durur.
- Tanım:
DEFINE_GET_STRING.
- Ekranı temizler ve imleci en üste (0, 0) taşır.
- Tanım:
DEFINE_CLEAR_SCREEN.
LEA DI, ad ; tampon MOV DX, 20 ; boyut CALL get_string CALL clear_screen LEA SI, ad CALL print_string RET ad DB 20 DUP(0)
Prosedürler
Sayı Prosedürleri
| Prosedür | Ne yapar? | Girdi / çıktı | Tanım |
|---|---|---|---|
SCAN_NUM | Klavyeden çok haneli, işaretli bir sayı okur (Enter ile biter). | çıktı: CX | DEFINE_SCAN_NUM |
PRINT_NUM | AX'teki işaretli sayıyı onluk olarak yazar. | girdi: AX | DEFINE_PRINT_NUM + DEFINE_PRINT_NUM_UNS |
PRINT_NUM_UNS | AX'teki işaretsiz sayıyı yazar. | girdi: AX | DEFINE_PRINT_NUM_UNS |
16 bit: −32 768 … 32 767
16 bit: 0 … 65 535
FFE7h = −25 (işaretli) = 65 511 (işaretsiz)
Prosedürler
Demo: PRINT_NUM ve PRINT_NUM_UNS
AX'e bir değer verin (onluk, negatif ya da h ekli onaltılık): iki prosedürün ekrana ne yazacağını görün.
Örnek Program · Kodu adım adım çalıştır
Kod İzleme: Sayı Oku ve Yazdır
LEA SI, msg1: SI ← msg1 dizgesinin bağıl konumu (offset).
CALL print_string: dönüş adresi yığına itilir (SP = FFFCh); prosedür DS:SI'deki dizgeyi 0'a kadar yazar.
CALL scan_num: kullanıcı -25 yazıp Enter'a basar; karakterler ekrana yankılanır.
Dönüş: CX = FFE7h = −25 (ikiye tümleyen). SP yeniden FFFEh.
MOV AX, CX: PRINT_NUM sayıyı AX'te bekler.
CALL pthis: yığına itilen “dönüş adresi” aslında bir sonraki satırdaki dizgenin adresidir.
PTHIS dizgeyi yazar: 13, 10 (yeni satır) ve “You have entered: ”. Sonra dönüş adresini 0'ın ötesine taşır.
Dönüş, dizgenin sonrasına yapılır. CALL print_num: AX = FFE7h işaretli yazılır.
RET: DOS'a dönüş. Satır 11–17 veri ve prosedür tanımlarıdır, akışta çalıştırılmaz.
include 'emu8086.inc' ORG 100h LEA SI, msg1 ; ask for the number CALL print_string ; CALL scan_num ; get number in CX. MOV AX, CX ; copy the number to AX. CALL pthis ; print the following string: DB 13, 10, 'You have entered: ', 0 CALL print_num ; print number in AX. RET ; return to operating system. msg1 DB 'Enter the number: ', 0 DEFINE_SCAN_NUM DEFINE_PRINT_STRING DEFINE_PRINT_NUM DEFINE_PRINT_NUM_UNS ; required for print_num. DEFINE_PTHIS END ; directive to stop the compiler.
Örnek Program
PTHIS Nasıl Çalışır?
Bellekte CALL pthis'in hemen ardından dizge baytları gelir; dizge 0 ile biter.
CALL, “sonraki komutun” adresini iter. Bu adres, dizgenin ilk baytı olan 0Dh'nin adresidir.
PTHIS yığındaki adresi okur ve oradan itibaren baytları 0'a kadar ekrana yazar.
Yığındaki adres, 0 baytının bir ötesiyle değiştirilir: artık CALL print_num'u gösterir.
RET: işlemci dizgeyi atlayıp CALL print_num'dan devam eder. Veri komut sanılıp çalıştırılmaz.
JMP ile atlar.Örnek Program
Sık Yapılan Hatalar
CALL scan_num var ama DEFINE_SCAN_NUM yoksa derleyici etiketi bulamaz: undefined hatası.
Tanımlar ORG 100h'nin hemen altına konursa işlemci prosedür kodunu ana program sanarak çalıştırır. Yeri: RET ile END arası.
PRINT_STRING ve PTHIS 0 görene kadar yazar; 0 yoksa bellekteki rastgele baytlar ekrana dökülür.
Prosedürler sonuçlarını belirli yazmaçlarda döndürür (SCAN_NUM → CX). Başka yazmaçtaki değerin korunduğu belgede yazmıyorsa varsayılmamalıdır.
CALL Komutu
CALL Komutu
- Derleyici ilk aşamada
DEFINE_…tanımlarını işler; bunlar prosedürlere genişleyen normal makrolardır. CALLtalimatı prosedürleri çağırmak için kullanılır.- Derleyici
CALL'daki prosedür adını, prosedürün bulunduğu adrese dönüştürür. CALLyürütüldüğünde dönüş adresi yığına itilir ve kontrol prosedüre aktarılır; prosedürRETile geri döner.- Prosedür kodu dosyada bir kez bulunur: aynı prosedür 100 kez çağrılsa da gövdesi çoğalmaz; her çağrı yalnızca 3 baytlık bir
CALLekler. - Bu yaklaşım yürütülebilir dosyanın boyutunu küçük tutar.
CALL Komutu
CALL ve RET Adım Adım
CALL print_num 0110h adresinde, 3 bayt (E8 + 16 bit bağıl uzaklık). Sonraki komut 0113h'de. (Örnek adresler.)
1) SP ← SP − 2, dönüş adresi 0113h yığına yazılır.
2) IP ← prosedürün adresi (ör. 0200h). Prosedür çalışır.
RET: IP ← [SP] = 0113h, SP ← SP + 2. Ana program kaldığı yerden sürer.
PUSH edilen her değer RET'ten önce POP edilmelidir; yoksa RET yanlış adrese döner.CALL Komutu
Makro mu, Prosedür mü?
| Ölçüt | Makro | Prosedür |
|---|---|---|
| Ne zaman işlenir? | derleme sırasında metin olarak açılır | çalışma sırasında CALL ile çağrılır |
| Kod boyutu | her kullanımda kopya | tek kopya + çağrı başına 3 bayt |
| Hız | CALL/RET yükü yok, biraz daha hızlı | her çağrıda yığın işlemi |
| Parametre | makro argümanları | yazmaçlar veya yığın |
| emu8086.inc | PUTC, GOTOXY, PRINT … | PRINT_NUM, SCAN_NUM … (DEFINE_ gerekli) |
Özet
Özet
include 'emu8086.inc': önce kaynak klasörü, sonra Inc klasörü aranır.
PUTC, GOTOXY (col, row), PRINT, PRINTN, CURSOROFF, CURSORON: INT 10h üzerine kurulu, kullanıldıkları yere açılır.
END'den önce DEFINE_…, kullanırken CALL. Girdi/çıktı yazmaçları: SI, DI, DX, CX, AX.
SCAN_NUM → CX (işaretli); PRINT_NUM AX'i işaretli, PRINT_NUM_UNS işaretsiz yazar.
Dizge CALL'dan hemen sonra; prosedür dönüş adresini dizgenin sonrasına taşır.
CALL dönüş adresini iter ve atlar; RET adresi çekip döner. Prosedür kodu bir kez bulunur.
Özet
Alıştırmalar
- Ekranın ortasına (sütun 35, satır 12) “MERKEZ” yazan programı makrolarla yazın.
- Kullanıcıdan iki sayı okuyup toplamını yazdıran programı yazın.
PRINTmakrosu 10 kez kullanılırsa dizgeler ve döngü kodu kaç kez bulunur? PRINT_STRING ile karşılaştırın.- AX = 8000h iken PRINT_NUM ve PRINT_NUM_UNS ne yazar?
DEFINE_PTHIS,ORG 100h'nin hemen altına yazılırsa ne olur?- Kullanıcının adını GET_STRING ile alıp “Merhaba, ad!” yazdırın.
İpuçları / cevaplar
GOTOXY 35, 12ardındanPRINT 'MERKEZ',RET.CALL scan_num→MOV BX,CX→CALL scan_num→MOV AX,BX,ADD AX,CX,CALL print_num; DEFINE_SCAN_NUM, DEFINE_PRINT_NUM, DEFINE_PRINT_NUM_UNS.- PRINT: 10 kopya (her biri kendi dizgesi ve döngüsüyle). PRINT_STRING: döngü 1 kez, 10 dizge + 10 × (LEA + CALL).
- PRINT_NUM: −32768, PRINT_NUM_UNS: 32768.
- Program başlarken doğrudan PTHIS'in koduna girer; yığında geçerli dizge adresi olmadığından anlamsız çıktı veya kilitlenme.
LEA DI,ad / MOV DX,20 / CALL get_string,PRINT 'Merhaba, ',LEA SI,ad / CALL print_string,PUTC '!'.
Özet
Kaynaklar
- emu8086 yardım belgeleri: “emu8086.inc — library of common functions” ve “Macros” sayfaları.
- emu8086 kurulumundaki
Inc/emu8086.incdosyası (makro ve prosedürlerin kaynak kodu). - B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009 — prosedürler ve makrolar.
- A. S. Tanenbaum, Modern Operating Systems, 3. baskı, Pearson, 2008 (kaynak sunumda faydalanılmıştır).