Mikroişlemciler · Ders Notu
Bölüm 5.2: Kesme Fonksiyonları
Bir 8086 programı ekrana yazı yazmak, klavyeden tuş okumak ya da saati öğrenmek için donanımı her seferinde baştan sürmek zorunda değildir. Bilgisayarın ROM'undaki BIOS ve onun üstünde çalışan DOS, bu işleri hazır yordamlar olarak sunar. Program bu yordamlara bir yazılım kesmesiyle ulaşır: AH yazmacına hizmet numarasını, öteki yazmaçlara parametreleri yazar ve INT n komutunu çalıştırır. Not, en sık kullanılan dört kesmenin hizmetlerini ele alır: INT 10h ekranı, INT 16h klavyeyi, INT 21h DOS'un karakter, dizgi, tarih ve saat hizmetlerini, INT 1Ah ise saat sayacını yönetir. Ekran belleğine BIOS'suz doğrudan yazma, BIOS veri alanı ve programı doğru sonlandırma yolları da işlenir. Her hizmet, kısa bir programın adım adım izlemesiyle yazmaç düzeyinde gösterilir.
Öğrenme çıktıları
- Hizmet çağırmak
- BIOS ve DOS hizmetlerini AH'deki hizmet numarası ve yazmaç parametreleriyle çağırmak; hangi yazmaçların değiştiğini önceden bilmek.
- Ekrana yazmak
- INT 10h ve INT 21h ile karakter, renkli karakter ve dizgi yazdırmak; imleci konumlamak; öznitelik baytını kurmak; B800h ve A000h belleğine doğrudan yazmak.
- Klavyeden okumak
- INT 16h ve INT 21h ile tuş okumak, tarama kodunu ASCII kodundan ayırmak, tuş beklemeden yoklamak ve tamponlu satır girişi almak.
- Saati okumak
- Tarih ve saati DOS'tan ikili, RTC'den paketli BCD olarak okuyup ekrana yazdırmak; BIOS veri alanındaki tık sayacıyla süre ölçmek.
- Programı sonlandırmak
- Programı RET, INT 20h ya da INT 21h/4Ch ile doğru biçimde bitirmek; COM ve EXE şablonlarının farkını açıklamak.
- Program izlemek
- Hizmet kullanan bir programı adım adım izleyip yazmaç, bayrak, bellek ve ekran durumunu her adımda belirlemek.
5.2.1BIOS ve DOS hizmetleri
5.2.1.1Hizmet katmanları
Ekrana tek bir karakter yazmak, donanım düzeyinde birkaç ayrı iş demektir. Karakterin kodu, ekran kartının belleğinde doğru hücreye yazılır. Hücrenin renk baytı ayarlanır. İmlecin yeni konumu ekran kartındaki denetleyiciye bir G/Ç portu üzerinden bildirilir. Satır sonuna gelinmişse alt satıra geçilir, ekranın sonunda ise bütün satırlar bir yukarı kaydırılır. Her programın bu işleri kendisi yapması hem zahmetli hem de tehlikelidir. Ekran kartı değişince programların hepsi yeniden yazılmak zorunda kalır.
IBM PC uyumlu bilgisayarlar bu sorunu katmanlarla çözer. Şekil 5.2.1 dört katmanı gösterir. En altta donanım vardır: ekran kartı, klavye denetleyicisi, disk ve saat. Donanıma doğrudan G/Ç portları (IN, OUT) ve bellek adresleri üzerinden ulaşılır. Bir üstte BIOS durur. BIOS'un yordamları donanımın ayrıntısını bilir ve bunu sabit bir arayüzün arkasına saklar. Onun üstündeki DOS, dosya, dizgi, tarih ve program yönetimi gibi daha soyut hizmetler sunar. En üstte uygulama programı vardır; o yalnız bu hizmetleri çağırır.
INT 21h ile, BIOS'u INT 10h, INT 16h, INT 1Ah gibi kesmelerle çağırır. DOS kendi işinin çoğunu BIOS'a yaptırır; BIOS donanıma IN/OUT komutlarıyla ve bellek erişimiyle ulaşır.BIOS (Basic Input/Output System, temel giriş/çıkış sistemi), anakarttaki ROM'da bulunan ve donanımı doğrudan süren yordamlar topluluğudur. İşletim sistemi olmadan da çalışır. Bilgisayar açılınca donanımı sınar, kesme vektör tablosuna kendi yordamlarının adreslerini yazar ve işletim sistemini diskten yükler. DOS (Disk Operating System) ise BIOS'un üstünde çalışan, dosya, bellek ve program yönetimi sunan işletim sistemidir.
Bir programın BIOS ya da DOS hizmetine ulaşmak için kullandığı araç yazılım kesmesidir (software interrupt). INT n komutu, işlemcinin bellekteki kesme vektör tablosundan n numaralı girişi okuyup oradaki adrese dallanmasını sağlar. Dönüş adresi ve bayraklar yığına itilir; hizmet yordamı işini bitirince IRET ile programa döner. Buradaki konu bu mekanizmanın kendisi değil, onun sunduğu hizmetlerdir. Önemli olan şudur: program hizmetin bellekteki adresini bilmek zorunda değildir. Yalnız numarasını bilir.
Adres yerine numara kullanmanın yararı büyüktür. Farklı üreticilerin BIOS'ları yordamlarını farklı adreslere yerleştirir. DOS'un hangi sürümünün yüklü olduğu da adresleri değiştirir. Vektör tablosu açılışta o makinenin gerçek adresleriyle doldurulur. Böylece INT 10h yazan bir program, her PC uyumlu makinede kendi ekran yordamına ulaşır. 8086 üzerinde INT n komutu 51 saat turu sürer; doğrudan uzak CALL 28 turdur. Bedel neredeyse iki kat süredir, karşılığı taşınabilirliktir.
Aynı iş farklı katmanlarda yapılabilir. Ekrana bir karakter yazmanın üç yolu vardır: DOS'un INT 21h/02h hizmeti, BIOS'un INT 10h/0Eh hizmeti ve ekran belleğine (B800h kesimi) doğrudan yazma. Üst katman daha taşınabilirdir; çıktısı bir dosyaya da yönlendirilebilir. Alt katman daha hızlı ve esnektir; renk ve konum üzerinde tam denetim verir. Program, işin gereğine göre katmanı seçer ve aynı programda katmanları karıştırabilir.
5.2.1.2Hizmet çağırma kalıbı
Bir kesme numarası tek bir hizmete değil, bir hizmet ailesine karşılık gelir. INT 21h karakter yazmak, dizgi yazmak, dosya açmak, saati okumak ve programı bitirmek gibi yüzlerce iş yapar. Hangi işin yapılacağını kesmeden önce AH yazmacına yazılan sayı belirler. Bu sayıya hizmet numarası ya da fonksiyon numarası denir. AH 8 bitlik olduğu için bir kesmenin en çok 256 hizmeti olabilir.
Hizmet çağırma kalıbı dört adımdan oluşur: (1) AH ← hizmet numarası; (2) öteki parametreler AL, BX, CX, DX, DS:DX ya da ES:BP gibi yazmaçlara yazılır; (3) INT n çalıştırılır; (4) sonuç yazmaçlardan (AL, AX, CX, DX) ya da bayraklardan (ZF, CF) okunur. Hangi yazmacın ne taşıdığı her hizmet için ayrı tanımlıdır.
En kısa örnek, DOS'a ekrana bir harf yazdırmaktır:
mov ah, 02h ; hizmet: karakter yaz
mov dl, 'A' ; parametre
int 21h ; DOS'u çağırBirinci satır AH'ye 02h yükler: DOS'un “karakter yaz” hizmeti. İkinci satır yazılacak karakterin ASCII kodunu, 41h'yi DL'ye koyar. Bu hizmet karakteri DL'de bekler. Üçüncü satır kesmeyi çağırır. İşlemci 0000:0084h adresindeki vektörü okur (21h × 4 = 84h), DOS'un yordamına dallanır. Yordam karakteri imlecin bulunduğu yere yazar, imleci bir ilerletir ve IRET ile döner. Program, int 21h'den sonraki komuttan devam eder.
Bu kalıpta işlemcinin donanım düzeyinde yaptığı iş bellidir. MOV AH, 02h iki baytlık bir komuttur (B4 02); BIU onu önden getirme kuyruğundan alır, EU yazmaca yazar ve bellek yol döngüsü gerekmez. INT 21h ise yığına üç sözcük iter (FLAGS, CS, IP) ve vektör tablosundan iki sözcük okur: beş bellek yol döngüsü. Hizmet yordamının kendisi yüzlerce komuttur. Dolayısıyla tek karakter yazdırmak bile binlerce saat turu sürer. Bu süre kullanıcının fark edemeyeceği kadar kısadır, ama ekranı karakter karakter dolduran bir döngüde belirginleşir.
Tablo 5.2.1 sık kullanılan kesmeleri ve sağlayıcılarını listeler.
| Kesme | Sağlayan | Görev |
|---|---|---|
INT 10h | BIOS | video: mod, imleç, karakter, dizgi, piksel |
INT 13h | BIOS | disk |
INT 16h | BIOS | klavye |
INT 1Ah | BIOS | saat sayacı, gerçek zamanlı saat |
INT 20h | DOS | programı sonlandır (COM) |
INT 21h | DOS | yüzlerce hizmet: karakter ve dizgi G/Ç, dosya, tarih ve saat, çıkış |
Hizmetler kendi kullandıkları yazmaçları değiştirebilir. Bu, kalıbın en çok hata doğuran yanıdır. Örneğin INT 21h/02h dönüşte AL'ye DL'deki karakteri koyar; INT 21h/09h ise AL'yi 24h yapar. AL'de saklanan bir değer bu çağrılardan sonra kaybolur. Sonra gerekecek değerler, hizmetin dokunmadığı bir yazmaçta ya da yığında tutulur. Bazı hizmetler AL'yi de bir alt seçim için kullanır. VESA ekran kartı hizmetleri buna örnektir: AX = 4F00h ile çağrılan hizmette AH = 4Fh aileyi, AL = 00h o ailedeki işi seçer.
Okunan bir karakteri AL'de bırakıp araya başka bir INT 21h çağrısı koymak. Örneğin önce AH = 01h ile tuş okunur, sonra satır başı için AH = 02h, DL = 0Dh çağrılır. Bu çağrı AL'yi 0Dh yapar ve okunan tuş kaybolur. Okunan değer çağrıdan hemen sonra BL gibi başka bir yazmaca kopyalanmalıdır.
5.2.1.3ASCII ve denetim karakterleri
Ekrana yazılan ve klavyeden okunan her karakter bir sayıdır. PC'de bu sayılar ASCII (American Standard Code for Information Interchange) kodlamasından gelir. ASCII 0–127 arasındaki kodlara karakter atar. 20h–7Eh arası basılabilir karakterlerdir: boşluk, rakamlar, harfler ve noktalama. 00h–1Fh arası ise denetim karakterleridir (control characters). Bunlar ekranda bir şekil olarak değil, bir eylem olarak anlam taşır.
| Kod | Ad | Etki |
|---|---|---|
| 07h | BEL | zil sesi |
| 08h | BS | imleç bir geri (karakter silinmez) |
| 09h | TAB | sekme (DOS hizmetlerinde) |
| 0Ah | LF | imleç bir alt satıra |
| 0Dh | CR | imleç satır başına; Enter tuşunun kodu |
| 1Bh | ESC | Esc tuşunun kodu |
Basılabilir karakterlerin kodları rastgele dağılmamıştır; birkaç düzen, programları kısaltır. Tablo 5.2.3 bu düzenleri özetler. Rakamların kodu 30h'den başlar: '0' = 30h, '9' = 39h. Bu yüzden bir rakamın sayı değeri, kodundan 30h çıkarılarak bulunur. Tersine, 0–9 arasındaki bir sayı 30h eklenerek ekrana yazılabilir bir rakama dönüşür. Büyük harfler 41h–5Ah, küçük harfler 61h–7Ah arasındadır. İki grup arasındaki fark tam 20h'dir, yani tek bir bit: bit 5. Küçük harfi büyüğe çevirmek için bit 5 silinir (SUB AL, 20h ya da AND AL, 0DFh); büyüğü küçüğe çevirmek için kurulur (OR AL, 20h).
| Karakter | ASCII | İlişki |
|---|---|---|
| boşluk | 20h | basılabilir karakterlerin ilki |
| '0' … '9' | 30h–39h | rakam = kod − 30h |
| 'A' … 'Z' | 41h–5Ah | bit 5 = 0 |
| 'a' … 'z' | 61h–7Ah | bit 5 = 1 (+20h) |
| '$' | 24h | INT 21h/09h hizmetinde dizgi sonu |
Yeni satıra geçmek iki ayrı karakter ister: CR (0Dh) ve LF (0Ah). Bu ayrım daktilodan kalmadır. CR, yazı kafasını satırın başına döndürür; LF, kâğıdı bir satır yukarı iter. Şekil 5.2.2 üç durumu karşılaştırır. Yalnız CR gönderilirse imleç satır başına döner ve sonraki yazı aynı satırın üzerine gelir. Yalnız LF gönderilirse imleç bir alt satıra iner ama sütunu değişmez; metin merdiven gibi sağa kayar. İkisi birlikte gönderilince imleç alt satırın başına gelir.
Türkçe harfler (ç, ğ, ı, ö, ş, ü) 7 bitlik ASCII'de yoktur. DOS bunları 128–255 arasındaki kodlarla, etkin kod sayfasına (code page) göre gösterir; Türkçe için bu sayfa CP857'dir. Aynı bayt başka bir kod sayfasında başka bir harf olarak görünebilir. Bu yüzden sunumdaki ve bu nottaki örnek programlar dizgilerde Türkçe harf kullanmaz: 'Cikis', 'Car' gibi.
AL = 37h ('7') ve BL = 32h ('2') iki rakam karakteridir. Toplamlarını tek basamak olarak ekrana yazmak için önce ikisinden de 30h çıkarılır: 07h ve 02h. Toplam 09h'dir. Ekrana yazmak için 30h eklenir: 39h = '9'. Karakterler doğrudan toplansaydı 37h + 32h = 69h = 'i' çıkardı. ASCII kodları sayı değil, karakter adıdır; aritmetikten önce sayıya çevrilir.
5.2.2INT 10h: video hizmetleri
5.2.2.1Hizmet tablosu ve video modları
Ekranla ilgili BIOS hizmetlerinin hepsi INT 10h altında toplanır. Ekran modunu seçmek, imleci taşımak, renkli karakter yazmak, bir dizgiyi tek çağrıyla basmak, ekranın bir bölgesini silmek ve grafik modda piksel çizmek bu hizmetlerle yapılır. Tablo 5.2.4 en sık kullanılanları, giriş ve çıkış yazmaçlarıyla verir.
| AH | Hizmet | Giriş | Çıkış / açıklama |
|---|---|---|---|
| 00h | video modu seç | AL = mod (03h: 80×25 renkli metin) | ekran temizlenir |
| 01h | imleç şekli | CH = başlangıç, CL = bitiş satırı | CH = 20h → imleç gizli |
| 02h | imleci konumla | BH = sayfa, DH = satır, DL = sütun | – |
| 03h | imleç konumunu oku | BH = sayfa | DH, DL = konum; CH, CL = şekil |
| 06h | pencereyi yukarı kaydır | AL = satır sayısı (0 = temizle), BH = öznitelik, CH,CL – DH,DL = köşeler | ekranı ya da bir pencereyi siler |
| 09h | karakter ve öznitelik yaz | AL = karakter, BH = sayfa, BL = öznitelik, CX = tekrar | imleç ilerlemez |
| 0Ah | yalnız karakter yaz | AL, BH, CX | hücrenin özniteliği korunur |
| 0Ch | piksel yaz | AL = renk, BH = sayfa, CX = x, DX = y | grafik modlarda |
| 0Eh | teletype çıkışı | AL = karakter, BH = sayfa | imleç ilerler; CR, LF, BS, BEL yorumlanır |
| 13h | dizgi yaz | AL = mod, BH, BL, CX = uzunluk, DH,DL = konum, ES:BP = dizgi | AT ve sonraki BIOS'larda |
Ekran kartı farklı video modlarında (video mode) çalışabilir. Metin modlarında ekran, her biri bir karakter tutan hücrelerden oluşur. Grafik modlarında ise ekran piksellerden oluşur ve her pikselin rengi ayrı ayrı yazılır. Mod, AH = 00h hizmetiyle AL'deki numara verilerek seçilir. Tablo 5.2.5 sık kullanılan modları ve görüntü belleğinin hangi kesimde başladığını gösterir.
| AL | Mod | Görüntü belleği |
|---|---|---|
| 01h | 40×25 metin, 16 renk | B800h |
| 03h | 80×25 metin, 16 renk | B800h |
| 07h | 80×25 tek renk | B000h |
| 04h | 320×200 grafik, 4 renk | B800h |
| 13h | 320×200 grafik, 256 renk | A000h |
Mod seçmek ekranı da temizler. Bu yüzden programların başında sık görülen iki satır, temiz bir 80×25 ekran elde etmenin en kısa yoludur:
mov ah, 00h
mov al, 03h ; ya da mov ax, 0003h
int 10h ; temiz 80×25 ekranAH ve AL tek bir MOV AX, 0003h komutuyla birlikte yüklenebilir. AH, AX'in yüksek baytı olduğundan 00h, AL düşük baytı olduğundan 03h olur. Üç baytlık bu komut, iki baytlık iki ayrı MOV'dan hem kısa hem hızlıdır.
Mod 03h'te ekran 25 satır ve 80 sütundur (Şekil 5.2.3). Satırlar 0'dan 24'e, sütunlar 0'dan 79'a numaralanır. Sol üst köşe (0, 0), sağ alt köşe (24, 79)'dur. BIOS hizmetlerinde satır numarası DH'de, sütun numarası DL'de verilir. emu8086'nın ekran penceresi varsayılan olarak bu moddadır; grafik modlarını sınırlı destekler.
5.2.2.2İmleç
İmleç (cursor), ekranda bir sonraki karakterin yazılacağı konumdur. BIOS her görüntü sayfası için bir imleç konumu tutar. AH = 02h imleci DH satırına ve DL sütununa taşır; AH = 03h imlecin konumunu DH ve DL'ye okur. İki hizmet de BH'de bir görüntü sayfası numarası bekler. 80×25 modunda ekran kartının belleği birden çok ekranı tutacak kadar büyüktür; VGA'da 8 sayfa (0–7) vardır. Sayfalardan yalnız biri görünür. Normalde sayfa 0 kullanılır.
Satır ve sütun, tek bir MOV DX komutuyla birlikte yüklenebilir. mov dx, 0C28h DH'ye 0Ch = 12, DL'ye 28h = 40 yazar: ekranın ortası. Aşağıdaki kod önce imleci ortaya alır, sonra konumu okuyup bir sağa kaydırır.
; imleci ortaya al
mov ah, 02h
mov bh, 0
mov dx, 0C28h ; 12. satır, 40. sütun
int 10h
; imleci bir sağa kaydır
mov ah, 03h
mov bh, 0
int 10h ; DH, DL = konum
inc dl
mov ah, 02h
int 10hİlk dört satır imleci (12, 40)'a taşır. Sonraki üç satır konumu okur; dönüşte DH = 12, DL = 40 olur ve CH, CL'ye imlecin şekli yazılır. INC DL sütunu 41 yapar. Son iki satır yeni konumu yazar. BH, 03h çağrısından sonra değişmediği için yeniden yüklenmez. Şekil 5.2.4 bu adımları ve hücrenin ekran belleğindeki yerini gösterir.
mov dx, 0C28h imleci (12, 40)'a koyar; 03h ile okunup inc dl ile artırılan konum 02h ile yazılınca imleç (12, 41)'e geçer.İmleç konumu yalnız BIOS'un bir değişkeni değildir; ekran kartının donanımında da tutulur. Renkli metin modunda ekran denetleyicisinin (CRTC) iki yazmacı, imlecin hangi hücrede yanıp söneceğini belirler. BIOS bu yazmaçlara 3D4h (indis) ve 3D5h (veri) G/Ç portları üzerinden OUT komutlarıyla yazar. AH = 02h çağrısı, programı bu port ayrıntısından kurtarır. Aynı konum BIOS veri alanında da saklanır; INT 21h ile yazılan karakterler de bu imleç konumundan başlar.
Her hücrenin ekran belleğinde de bir yeri vardır. Mod 03h'te hücre başına 2 bayt kullanılır ve satırlar art arda dizilir. (satır, sütun) hücresinin bağıl konumu şöyle hesaplanır:
bağıl konum = (satır × 80 + sütun) × 2
(12, 40) için (960 + 40) × 2 = 2000 = 07D0h bulunur. (1, 4) için (80 + 4) × 2 = 168 = 00A8h'dir. Çift adreste karakterin kodu, onu izleyen tek adreste rengi durur.
5.2.2.3Öznitelik baytı
Metin modunda her hücrenin rengi bir baytla belirlenir. Bu bayta öznitelik baytı (attribute byte) denir. Şekil 5.2.5 baytın bitlerini gösterir. Düşük dört bit (bit 3–0) ön planın, yani yazının rengidir. Bit 2–0 kırmızı, yeşil ve mavi bileşenleri açar; bit 3 rengi parlaklaştırır. Bit 6–4 arka planın rengidir: yine kırmızı, yeşil, mavi. Bit 7 ise karakterin yanıp sönmesini açar.
Öznitelik baytı, metin modunda bir karakter hücresinin ön ve arka plan rengini ve yanıp sönmesini belirleyen bayttır. Onaltılık yazıldığında yüksek basamak arka planı, düşük basamak ön planı verir: öznitelik = arka plan × 16 + ön plan. Bit 7 = 1 ise karakter yanıp söner (BIOS ayarına göre arka plan parlak da gösterilebilir).
On altı renk, dört bitin bütün birleşimlerinden çıkar. Tablo 5.2.6 numaraları ve adları verir. Parlak renkler (8–F), karanlık karşılıklarına bit 3'ün eklenmesiyle oluşur: 1 mavi, 9 açık mavi; 4 kırmızı, C açık kırmızı. İki istisna dikkat çeker: 6 sarı değil kahverengidir, parlak hâli E ise sarıdır. 7 açık gri, F beyazdır.
| No | Renk | No | Renk |
|---|---|---|---|
| 0 | siyah | 8 | koyu gri |
| 1 | mavi | 9 | açık mavi |
| 2 | yeşil | A | açık yeşil |
| 3 | camgöbeği | B | açık camgöbeği |
| 4 | kırmızı | C | açık kırmızı |
| 5 | eflatun | D | açık eflatun |
| 6 | kahverengi | E | sarı |
| 7 | açık gri | F | beyaz |
Varsayılan öznitelik 07h'dir: arka plan 0 (siyah), ön plan 7 (açık gri). Mavi zemin üzerine beyaz yazı için arka plan 1, ön plan F seçilir: 1 × 16 + 15 = 31 = 1Fh. Kırmızı zemin üzerine sarı yazı 4Eh'dir. 8Fh = 1000 1111b ise bit 7 kurulu olduğu için siyah zemin üzerinde yanıp sönen beyaz yazıdır. Arka plana yalnız üç bit ayrıldığından açık yeşil (A) zemin doğrudan seçilemez: A0h yazılırsa en üstteki 1 biti bit 7'ye düşer ve yeşil zemin üzerinde yanıp sönme açılır.
Sunumdaki öznitelik gezgini, ön plan ve arka plan seçildiğinde öznitelik baytını ve onu kullanan INT 10h/09h çağrısını üretir. Aynı hesap elle de kolaydır: iki renk numarası onaltılık iki basamak olarak yan yana yazılır.
5.2.2.4Karakter yazma: 09h ve 0Eh
INT 10h karakter yazmak için iki ana hizmet sunar ve ikisi çok farklı davranır. AH = 09h karakteri AL'den, rengini BL'den alır ve aynı karakteri CX kez yan yana yazar. İmleci ise ilerletmez. AH = 0Eh, teletype (daktilo) çıkışıdır: karakteri imlecin olduğu yere yazar ve imleci bir ilerletir. Satır sonunda alt satıra geçer, son satırda ekranı yukarı kaydırır. CR, LF, BS ve BEL karakterlerini de komut olarak yorumlar. Tablo 5.2.7 farkları yan yana koyar.
| Özellik | AH = 09h | AH = 0Eh (teletype) |
|---|---|---|
| Girişler | AL = karakter, BH = sayfa, BL = öznitelik, CX = tekrar | AL = karakter, BH = sayfa |
| Renk | var (BL) | metin modunda yok; hücrenin rengi korunur |
| İmleç | ilerlemez | ilerler; satır sonunda alt satıra geçer |
| CR, LF, BS, BEL | sembol olarak basılır (♪, ◘ …) | komut olarak yorumlanır |
| Ekran kaydırma | yok | son satırda ekran yukarı kayar |
| Tipik kullanım | renkli kutular, çerçeveler, aynı karakteri CX kez | düz metin akışı |
09h'nin imleci ilerletmemesi ilk bakışta tuhaf görünür, ama hizmetin amacına uygundur. Bir çerçevenin üst kenarını çizmek için aynı karakter yan yana CX kez yazılır; imlecin nereye gideceğine program karar verir. Renkli düz metin yazmak için iki yaygın yol vardır. Birincisinde her karakter 09h ile CX = 1 olarak renkli yazılır, sonra imleç 02h ile bir sağa taşınır. İkincisinde bütün dizgi tek çağrıda 13h ile yazılır.
09h ile art arda karakter yazıp imleci taşımamak. Her yeni karakter bir öncekinin üzerine yazılır ve ekranda yalnız sonuncusu görünür. 09h'den sonra imleç ya AH = 02h ile elle ilerletilir ya da renkli hücrenin üzerine 0Eh ile yazılır.
5.2.2.5Kod izleme: mod, imleç, 09h ve 0Eh
Aşağıdaki program dört hizmeti art arda kullanır. Önce ekranı temizler, imleci (1, 4)'e taşır, oraya kırmızı zemin üzerine sarı üç yıldız yazar, sonra teletype ile 'A' ve 'B' yazar. Programın amacı, 09h ile 0Eh'nin imleç ve renk üzerindeki farkını bir arada göstermektir.
org 100h
mov ax, 0003h ; AH=00h, AL=03h
int 10h ; ekran silinir
mov ah, 02h ; imleç konumla
mov bh, 0 ; sayfa 0
mov dx, 0104h ; DH=1, DL=4
int 10h
mov ah, 09h ; karakter + öznitelik
mov al, '*'
mov bl, 4Eh ; kırmızı üstüne sarı
mov cx, 3 ; 3 kez
int 10h ; imleç ilerlemez!
mov ah, 0Eh ; teletype
mov al, 'A'
int 10h ; imleç ilerler
mov al, 'B'
int 10h
retProgram bir .COM programıdır: org 100h ile başlar, başlangıçta genel yazmaçlar sıfırdır. İlk iki satır mod 03h'ü kurar. Ekran silinir ve imleç (0, 0)'a gelir. Sonraki dört satır imleci taşır. mov dx, 0104h komutu DH'ye 01h, DL'ye 04h yazar. Little-endian yerleşim nedeniyle komutun baytları BA 04 01'dir. int 10h'den sonra imleç (1, 4)'tedir ama ekranda henüz bir şey yoktur.
Ardından 09h çağrısı hazırlanır. AL = 2Ah ('*'), BL = 4Eh, CX = 3 yüklenir. BH hâlâ 0'dır; yeniden yazmak gerekmez. Çağrıdan sonra (1, 4), (1, 5) ve (1, 6) hücrelerinde kırmızı zemin üzerine sarı yıldızlar vardır. İmleç ise yerinden kıpırdamamıştır: hâlâ (1, 4).
Son kısımda AH = 0Eh yüklenir ve AL'ye 'A' yazılır. INT 10h, 'A'yı imlecin bulunduğu (1, 4)'e yazar; yani ilk yıldızın üzerine. Sonra imleci (1, 5)'e taşır. 0Eh hizmeti AH'yi değiştirmediği için ikinci karakterde yalnız AL değiştirilir. 'B', (1, 5)'teki ikinci yıldızın üzerine yazılır ve imleç (1, 6)'ya geçer. Ekranda AB* görünür. 0Eh metin modunda öznitelik almadığı için 'A' ve 'B', yıldızlardan kalan 4Eh rengini korur: kırmızı zemin üzerinde sarı.
| Adım | Komut | AX | BX | CX | DX | İmleç | Açıklama |
|---|---|---|---|---|---|---|---|
| 1 | mov ax, 0003h | 0003h | 0000h | 0000h | 0000h | (0, 0) | AH = 00h (mod seç), AL = 03h (80×25 metin) |
| 2 | int 10h | 0003h | 0000h | 0000h | 0000h | (0, 0) | mod kurulur, ekran silinir, imleç (0, 0) |
| 3 | mov ah, 02h | 0203h | 0000h | 0000h | 0000h | (0, 0) | AH = 02h: imleci konumla |
| 4 | mov bh, 0 | 0203h | 0000h | 0000h | 0000h | (0, 0) | BH = sayfa 0 |
| 5 | mov dx, 0104h | 0203h | 0000h | 0000h | 0104h | (0, 0) | DH = 1 (satır), DL = 4 (sütun) |
| 6 | int 10h | 0203h | 0000h | 0000h | 0104h | (1, 4) | imleç (1, 4)'e taşındı; ekran boş |
| 7 | mov ah, 09h | 0903h | 0000h | 0000h | 0104h | (1, 4) | AH = 09h: karakter + öznitelik |
| 8 | mov al, '*' | 092Ah | 0000h | 0000h | 0104h | (1, 4) | AL = '*' = 2Ah |
| 9 | mov bl, 4Eh | 092Ah | 004Eh | 0000h | 0104h | (1, 4) | BL = 4Eh: kırmızı zemin, sarı yazı |
| 10 | mov cx, 3 | 092Ah | 004Eh | 0003h | 0104h | (1, 4) | CX = 3 tekrar |
| 11 | int 10h | 092Ah | 004Eh | 0003h | 0104h | (1, 4) | (1, 4)–(1, 6) hücrelerine ***; imleç yerinde |
| 12 | mov ah, 0Eh | 0E2Ah | 004Eh | 0003h | 0104h | (1, 4) | AH = 0Eh: teletype |
| 13 | mov al, 'A' | 0E41h | 004Eh | 0003h | 0104h | (1, 4) | AL = 'A' |
| 14 | int 10h | 0E41h | 004Eh | 0003h | 0104h | (1, 5) | 'A' ilk yıldızın üzerine; imleç ilerledi |
| 15 | mov al, 'B' | 0E42h | 004Eh | 0003h | 0104h | (1, 5) | AL = 'B' |
| 16 | int 10h | 0E42h | 004Eh | 0003h | 0104h | (1, 6) | 'B' ikinci yıldızın üzerine: ekranda AB* |
| 17 | ret | 0E42h | 004Eh | 0003h | 0104h | (1, 6) | yığından 0000h → IP |
| 18 | INT 20h (PSP:0000h) | 0E42h | 004Eh | 0003h | 0104h | (1, 6) | PSP'deki INT 20h programı bitirir |
İzleme, BIOS hizmetlerinin yazmaçlara dokunma biçimini de gösterir. Hiçbir çağrı AX, BX, CX ya da DX'i değiştirmedi; yalnız ekranı ve imleci değiştirdi. INT 21h hizmetlerinin aksine bu INT 10h hizmetleri AL'yi korur. Yine de her hizmetin belgesine bakmadan bu güvene dayanmamak gerekir. AH = 03h gibi okuma hizmetleri dönüşte DX ve CX'i bilerek değiştirir.
5.2.2.6Dizgi yazma: 13h
AH = 13h, bir dizgiyi tek çağrıda ve renkli yazar. AT ve sonraki bilgisayarların BIOS'unda bulunur. Parametreleri çoktur: AL yazma modunu, BH sayfayı, BL özniteliği, CX dizginin uzunluğunu, DH ve DL başlangıç konumunu verir. Dizginin adresi ise ES:BP'dedir. Bu, DOS'un dizgi hizmetinden (DS:DX) farklıdır ve sık karıştırılır. Dizginin sonunda '$' gibi bir işaret aranmaz; uzunluk CX'ten alınır.
| AL | Dizginin biçimi | İmleç |
|---|---|---|
| 00h | yalnız karakterler; hepsi BL özniteliğinde | yerinde kalır |
| 01h | yalnız karakterler; hepsi BL özniteliğinde | dizginin sonuna ilerler |
| 02h | karakter, öznitelik çiftleri | yerinde kalır |
| 03h | karakter, öznitelik çiftleri | dizginin sonuna ilerler |
org 100h
mov ax, 1301h ; AH=13h, AL=01h
mov bx, 001Eh ; BH=0, BL=1Eh
mov cx, 7 ; dizgi uzunluğu
mov dx, 0205h ; satır 2, sütun 5
lea bp, mesaj ; ES:BP → dizgi
int 10h
ret
mesaj db 'Merhaba'Program dört yazmaç çiftini birer komutla yükler. AX = 1301h, AH = 13h ve AL = 01h demektir: bütün karakterler BL renginde, imleç ilerler. BX = 001Eh, BH = 0 sayfası ve BL = 1Eh rengidir; mavi zemin üzerinde sarı yazı. CX = 7, 'Merhaba' dizgisinin uzunluğudur. DX = 0205h başlangıcı satır 2, sütun 5'e koyar. LEA BP, mesaj, dizginin bağıl konumunu BP'ye yükler.
Dizginin bağıl konumu, önceki komutların bayt sayısından bulunur. Üç baytlık dört MOV 0100h–010Bh arasını kaplar. emu8086, doğrudan adresli LEA BP, mesaj komutunu MOV BP, OFFSET mesaj ile aynı üç baytlık koda (BD 12 01) derler; komut 010Ch–010Eh'dedir. İki baytlık INT 10h 010Fh–0110h'de, bir baytlık RET 0111h'dedir. mesaj bu yüzden 0112h'de başlar. Bir .COM programında bütün kesim yazmaçları aynı değeri gösterir, dolayısıyla ES = DS'dir ve ES:BP dizgiyi doğru gösterir.
| Adım | Komut | AX | BX | CX | DX | BP | İmleç | Açıklama |
|---|---|---|---|---|---|---|---|---|
| 1 | mov ax, 1301h | 1301h | 0000h | 0000h | 0000h | 0000h | (0, 0) | AH = 13h, AL = 01h (öznitelik BL'de, imleç ilerler) |
| 2 | mov bx, 001Eh | 1301h | 001Eh | 0000h | 0000h | 0000h | (0, 0) | BH = 0 (sayfa), BL = 1Eh (mavi zemin, sarı yazı) |
| 3 | mov cx, 7 | 1301h | 001Eh | 0007h | 0000h | 0000h | (0, 0) | dizgi uzunluğu 7 |
| 4 | mov dx, 0205h | 1301h | 001Eh | 0007h | 0205h | 0000h | (0, 0) | DH = 2, DL = 5: başlangıç konumu |
| 5 | lea bp, mesaj | 1301h | 001Eh | 0007h | 0205h | 0112h | (0, 0) | BP = mesaj'ın bağıl konumu; ES = DS |
| 6 | int 10h | 1301h | 001Eh | 0007h | 0205h | 0112h | (2, 12) | (2, 5)'ten başlayarak Merhaba; imleç (2, 12) |
| 7 | ret | 1301h | 001Eh | 0007h | 0205h | 0112h | (2, 12) | program biter |
| 8 | INT 20h (PSP:0000h) | 1301h | 001Eh | 0007h | 0205h | 0112h | (2, 12) |
Çağrı, (2, 5)'ten başlayarak yedi hücreye Merhaba yazar ve AL = 01h olduğu için imleci (2, 12)'ye taşır: 5 + 7 = 12. AL = 00h olsaydı dizgi yine yazılır, ama imleç (2, 5)'te kalırdı. AL = 02h ya da 03h seçilseydi dizgi her karakterden sonra kendi öznitelik baytını taşımalıydı; o zaman BL kullanılmaz ve CX yine karakter sayısıdır.
13h'te dizgi adresini DS:DX'e koymak ve DX'i iki kez kullanmak. DX bu hizmette konumdur; mov dx, offset mesaj yazılırsa konum bozulur, BP ise rastgele bir yeri gösterir. Bir başka hata, CX'i vermeyip dizginin sonuna '$' koymaktır. 13h '$' tanımaz; CX'te ne yazıyorsa o kadar karakter basar.
5.2.2.7Pencere kaydırma ve ekran temizleme: 06h
AH = 06h, ekranın dikdörtgen bir bölgesini, yani bir pencereyi, AL satır yukarı kaydırır. Pencerenin altında boşalan satırlar BH özniteliğiyle boşluk karakterine boyanır. AL = 0 verilirse kaydırma yerine pencerenin tamamı silinir. Bu özellik, ekranı mod değiştirmeden ve istenen renkte temizlemenin standart yoludur. AH = 07h aynı işi aşağı doğru yapar.
| Yazmaç | Anlamı |
|---|---|
| AL | kaydırılacak satır sayısı; 0 = pencereyi temizle |
| BH | boşalan satırların özniteliği |
| CH, CL | sol üst köşe (satır, sütun) |
| DH, DL | sağ alt köşe (satır, sütun) |
Aşağıdaki program önce bütün ekranı mavi zemine siler, sonra ortada kırmızı bir kutu açar.
org 100h
mov ax, 0600h ; AH=06h, AL=0
mov bh, 1Fh ; mavi/beyaz
mov cx, 0000h ; (0,0)
mov dx, 184Fh ; (24,79)
int 10h
mov ax, 0600h
mov bh, 4Fh ; kırmızı/beyaz
mov cx, 0714h ; (7,20)
mov dx, 103Bh ; (16,59)
int 10h
retİlk çağrıda köşeler CX = 0000h ve DX = 184Fh'dir. 18h = 24 ve 4Fh = 79 olduğundan pencere bütün ekrandır. BH = 1Fh, silinen hücrelere mavi zemin ve beyaz yazı rengini verir. Çağrıdan sonra ekranın her hücresinde boşluk karakteri ve 1Fh özniteliği vardır. Sonra yazılacak karakterler, 0Eh ile yazılsalar bile, bu rengi alır. Mod 03h'ü yeniden seçmek de ekranı siler, ama renkleri varsayılan 07h'ye döndürür.
İkinci çağrıda AX yeniden 0600h yapılır. Bu gereklidir, çünkü INT 10h'nin bazı BIOS'larda AX'i koruyacağı garanti edilmez. CX = 0714h sol üst köşeyi (7, 20), DX = 103Bh sağ alt köşeyi (16, 59) yapar. Kutu 16 − 7 + 1 = 10 satır ve 59 − 20 + 1 = 40 sütundur. Yalnız bu bölge kırmızıya silinir; dışı mavi kalır. İki çağrı da imleci yerinden oynatmaz; temizlikten sonra imleç AH = 02h ile (0, 0)'a ya da kutunun içine taşınır.
| Adım | Komut | AX | BX | CX | DX | Açıklama |
|---|---|---|---|---|---|---|
| 1 | mov ax, 0600h | 0600h | 0000h | 0000h | 0000h | AH = 06h (yukarı kaydır), AL = 0 (temizle) |
| 2 | mov bh, 1Fh | 0600h | 1F00h | 0000h | 0000h | BH = 1Fh: mavi zemin, beyaz yazı |
| 3 | mov cx, 0000h | 0600h | 1F00h | 0000h | 0000h | sol üst köşe (0, 0) |
| 4 | mov dx, 184Fh | 0600h | 1F00h | 0000h | 184Fh | sağ alt köşe (24, 79) |
| 5 | int 10h | 0600h | 1F00h | 0000h | 184Fh | tüm ekran mavi zemine silinir |
| 6 | mov ax, 0600h | 0600h | 1F00h | 0000h | 184Fh | ikinci çağrı için AH, AL yeniden |
| 7 | mov bh, 4Fh | 0600h | 4F00h | 0000h | 184Fh | BH = 4Fh: kırmızı zemin, beyaz yazı |
| 8 | mov cx, 0714h | 0600h | 4F00h | 0714h | 184Fh | sol üst (7, 20) |
| 9 | mov dx, 103Bh | 0600h | 4F00h | 0714h | 103Bh | sağ alt (16, 59) |
| 10 | int 10h | 0600h | 4F00h | 0714h | 103Bh | 10 satır × 40 sütunluk kutu kırmızıya silinir |
| 11 | ret | 0600h | 4F00h | 0714h | 103Bh | program biter |
Ekranın alt yarısını (satır 13–24) siyah zemine temizlemek için AX = 0600h ve BH = 07h yüklenir. Köşeler CX = 0D00h (satır 13, sütun 0) ve DX = 184Fh (satır 24, sütun 79) olur. Bir bölgeyi tek satır yukarı kaydırmak için ise AL = 1 verilir. AX = 0601h, CX = 1400h, DX = 184Fh ile satır 20–24 penceresi bir satır yukarı kayar. Satır 24 BH renginde boşalır.
5.2.3Görüntü belleğine doğrudan erişim
5.2.3.1B800h metin belleği
INT 10h hizmetleri sonunda hep aynı işi yapar: ekran kartının belleğine bayt yazar. Bu bellek, işlemcinin adres uzayında sıradan RAM gibi görünür. 8086'nın 1 MB'lık adres uzayında A0000h–BFFFFh aralığı ekran kartlarına ayrılmıştır. Renkli metin modlarında görüntü belleği B8000h fiziksel adresinden başlar; program ona B800h kesimiyle ulaşır. Ekran kartının denetleyicisi bu belleği saniyede onlarca kez baştan sona okur ve her hücreyi ekrana çizer. Belleğe yazılan değer, bir sonraki taramada ekranda görünür.
Görüntü belleği (video memory), ekran kartının ekranda gösterdiği içeriği tutan ve işlemcinin adres uzayına eşlenmiş bellektir. Mod 03h'te B800:0000h'dan başlayan 4000 bayttır (80 × 25 × 2). Her hücre iki bayt kaplar: çift adreste karakterin ASCII kodu, onu izleyen tek adreste öznitelik baytı.
Belleğe doğrudan yazmak, BIOS'u çağırmaktan çok daha hızlıdır. Bir INT 10h çağrısı yüzlerce komut yürütürken doğrudan yazma tek bir MOV komutudur. Bedeli de vardır. Doğrudan yazma imleci hareket ettirmez ve BIOS'un tuttuğu imleç bilgisini güncellemez. Çıktı DOS'un yönlendirmesine de girmez. Program, hücre adresini kendisi hesaplar ve ekran kartının hangi modda olduğunu bilmek zorundadır. emu8086 bu belleği destekler; yazılan hücreler ekran penceresinde görünür.
mov es:[di], ax ile AX = 4E41h yazılınca düşük bayt 41h ('A') çift adrese, yüksek bayt 4Eh (öznitelik) tek adrese gider.Hücreye bir sözcük olarak yazmak, karakter ile rengini tek komutta yerleştirir. 8086 little-endian'dır: bir sözcüğün düşük baytı küçük adrese, yüksek baytı büyük adrese yazılır. Bu yüzden AX'in AL yarısına karakter, AH yarısına öznitelik konur. Şekil 5.2.8 bu yerleşimi gösterir. Sözcüğün adresi çift olduğundan 8086 bu yazmayı tek bir yol döngüsünde yapar: veri yolunun 16 bitinin hepsi kullanılır, BHE ve A0 hatları birlikte etkin olur. Tek adrese sözcük yazmak ise iki ayrı yol döngüsü gerektirirdi.
5.2.3.2Kod izleme: B800h'e yazmak
Aşağıdaki program önce (1, 4) hücresine kırmızı zemin üzerine sarı bir 'A' koyar. Sonra REP STOSW ile ekranın ilk üç hücresini nokta karakteriyle doldurur. Sunumdaki biçimde ikinci kısım bütün ekranı doldurmak için CX = 2000 kullanır; izlenebilir kalsın diye burada CX = 3'tür.
org 100h
mov ax, 0B800h
mov es, ax
mov di, (1*80+4)*2 ; 00A8h
mov ax, 4E41h
mov es:[di], ax
xor di, di
mov ax, 072Eh
mov cx, 3 ; ilk 3 hücre
cld
rep stosw
retİlk iki satır ES'yi B800h yapar. Kesim yazmacına anlık değer doğrudan yazılamaz; MOV ES, 0B800h diye bir 8086 komutu yoktur. Bu yüzden değer önce AX'e alınır. Sayının başındaki 0, assembler'ın B800h'yi bir ad sanmaması içindir. Üçüncü satırdaki (1*80+4)*2 ifadesi derleme anında hesaplanır; makine koduna yalnız sonucu, 00A8h girer. Program çalışırken çarpma yapılmaz.
MOV ES:[DI], AX, ES kesimini açıkça adlandırır. DI ile yapılan bellek erişiminde varsayılan kesim DS'dir; burada DS programın kesimini gösterdiği için kesim öneki (26h baytı) zorunludur. Komut çalışınca fiziksel adres B800h × 16 + 00A8h = B80A8h'dir. Bu adrese 41h, B80A9h adresine 4Eh yazılır. Karakter anında ekranda görünür, imleç ise yerinde kalır. 8086 kılavuzuna göre bu komut 9 + EA turudur; [DI] için EA 5 tur, kesim öneki 2 tur ekler: yaklaşık 16 saat turu. Aynı karakteri INT 10h ile yazmak bunun yüzlerce katı sürer.
İkinci kısımda XOR DI, DI DI'yi sıfırlar; bu, MOV DI, 0'dan bir bayt kısadır. AX = 072Eh, AL = 2Eh ('.') ve AH = 07h (açık gri) demektir. CLD yön bayrağını (DF) temizler, böylece dizgi komutu DI'yi artırarak ilerler. REP STOSW her turda ES:[DI] ← AX yazar, DI'yi 2 artırır ve CX'i 1 azaltır; CX sıfır olunca durur. Üç tur sonunda DI = 0006h ve CX = 0'dır.
| Adım | Komut | AX | CX | DI | ES | DF | Açıklama |
|---|---|---|---|---|---|---|---|
| 1 | mov ax, 0B800h | B800h | 0000h | 0000h | 0700h | 0 | kesim değeri önce AX'e |
| 2 | mov es, ax | B800h | 0000h | 0000h | B800h | 0 | ES = B800h: metin ekranının kesimi |
| 3 | mov di, (1*80+4)*2 | B800h | 0000h | 00A8h | B800h | 0 | (1 × 80 + 4) × 2 = 168 = 00A8h |
| 4 | mov ax, 4E41h | 4E41h | 0000h | 00A8h | B800h | 0 | AL = 41h ('A'), AH = 4Eh (öznitelik) |
| 5 | mov es:[di], ax | 4E41h | 0000h | 00A8h | B800h | 0 | B80A8h ← 41h, B80A9h ← 4Eh; 'A' anında ekranda |
| 6 | xor di, di | 4E41h | 0000h | 0000h | B800h | 0 | DI = 0: sol üst hücre |
| 7 | mov ax, 072Eh | 072Eh | 0000h | 0000h | B800h | 0 | AL = 2Eh ('.'), AH = 07h |
| 8 | mov cx, 3 | 072Eh | 0003h | 0000h | B800h | 0 | üç hücre doldurulacak |
| 9 | cld | 072Eh | 0003h | 0000h | B800h | 0 | DF = 0: DI artarak ilerler |
| 10 | rep stosw | 072Eh | 0000h | 0006h | B800h | 0 | üç kez ES:[DI] ← AX, DI += 2 |
| 11 | ret | 072Eh | 0000h | 0006h | B800h | 0 | program biter |
2E 07, B800:00A8h'de 41 4E. Ekranın ilk satırında üç nokta, ikinci satırın 4. sütununda 'A' görünür.Bütün ekranı doldurmak için CX = 2000 verilir: 80 × 25 hücre. 8086'da REP STOSW yaklaşık 9 + 10 × CX saat turu sürer. 2000 hücre için bu 20 009 turdur; 5 MHz'lik bir işlemcide yaklaşık 4 ms eder. Aynı iş 2000 ayrı INT 10h/0Eh çağrısıyla yapılsaydı, kaydırma ve imleç güncellemesi yüzünden onlarca kat uzun sürerdi.
Karakter ve özniteliği ters yerleştirmek: mov ax, 414Eh yazılırsa düşük bayt 4Eh ('N') karakter, 41h ise mavi zemin üzerine mavi yazı rengi olur. Little-endian düzeninde karakter AL'de, öznitelik AH'dedir. İkinci yaygın hata, ES'yi ayarlamadan MOV [DI], AX yazmaktır. Kesim öneki olmadığında yazma DS kesimine, yani programın kendi verisinin üzerine gider.
5.2.3.3Mod 13h ve piksel adresi
Mod 13h, VGA'nın 320 × 200 çözünürlüklü, 256 renkli grafik modudur. mov ax, 0013h ve int 10h ile seçilir. Bu modun programcı için en büyük kolaylığı belleğin yapısıdır: her piksel tek bir bayttır ve pikseller satır satır art arda dizilir. Görüntü belleği A000:0000h'dan A000:F9FFh'ye kadar 64 000 bayttır (320 × 200). Baytın değeri pikselin renk numarasıdır; ekran kartı bu numarayı bir palet tablosunda gerçek renge çevirir. Varsayılan paletin ilk 16 rengi metin renkleriyle aynıdır: 0Eh sarı, 0Fh beyazdır.
Her satır 320 = 140h bayttır. (x, y) pikselinin bağıl konumu bu yüzden şöyle hesaplanır:
bağıl konum = y × 320 + x
(100, 50) pikseli için 50 × 320 + 100 = 16 100 = 3EE4h bulunur. Son piksel (319, 199), 199 × 320 + 319 = 63 999 = F9FFh'dedir; belleğin son baytı. Şekil 5.2.10 ilk satırların ve son satırın bağıl konumlarını gösterir.
BIOS bu modda da piksel hizmeti sunar. AH = 0Ch, AL'deki rengi CX sütunu (x, 0–319) ve DX satırındaki (y, 0–199) piksele yazar; BH sayfadır ve mod 13h'te 0'dır. AH = 0Dh aynı CX, DX ile pikselin rengini AL'ye okur. Koordinatla çalışmak kolaydır, ama her piksel için bir kesme çağrısı yavaştır.
Ekranın ortasındaki (160, 100) pikselinin bağıl konumu 100 × 320 + 160 = 32 160 = 7DA0h'dir; fiziksel adresi A0000h + 7DA0h = A7DA0h olur. Sağ üst köşe (319, 0) ise 013Fh'de, sol alt köşe (0, 199) 199 × 320 = 63 680 = F8C0h'dedir.
5.2.3.4Köşegen çizimi
Sol üst köşeden başlayan bir köşegen, (0, 0), (1, 1), (2, 2) … piksellerinden oluşur. Önce BIOS ile koordinat kullanan sürüm:
mov ax, 0013h
int 10h ; 320×200, 256 renk
xor cx, cx ; x = 0
xor dx, dx ; y = 0
mov bh, 0 ; sayfa
nokta: mov ax, 0C0Eh ; AH=0Ch, AL=sarı
int 10h
inc cx ; bir sağ
inc dx ; bir alt
cmp dx, 200
jb nokta ; 200 pikselDöngü her turda AX'i yeniden yükler. Bunun nedeni, bazı BIOS'ların 0Ch hizmetinde AX'i değiştirmesidir; güvenli yol her çağrıdan önce AH ve AL'yi kurmaktır. CX ve DX birlikte artar. DX 200'e ulaşınca JB atlamaz ve döngü 200 piksel çizmiş olarak biter. Ekran 320 piksel geniş olduğu için köşegen sağ kenara değil, alt kenara ulaşır.
Aynı çizgi, A000h belleğine doğrudan yazarak da çizilir. Bu kez koordinat yerine bağıl konumla çalışılır:
mov ax, 0013h
int 10h
mov ax, 0A000h
mov es, ax
xor di, di ; (0,0) → ofset 0
mov al, 0Eh ; sarı
mov cx, 200
ciz: mov es:[di], al
add di, 141h ; 320 + 1
loop ciz
mov ah, 0
int 16h ; tuş bekle
mov ax, 0003h
int 10h ; metin moduna dönNeden 141h eklenir? +140h (320) bir alt satırın aynı sütununa gider, +1 bir sağ sütuna. İkisi birlikte 141h = 321 eder ve köşegendeki bir sonraki pikseli verir. Son piksel (199, 199), 199 × 321 = 63 879 = F987h'dedir. Sağ üst köşeden inen ters köşegen için her adımda 13Fh (320 − 1) eklenir. Program sonunda bir tuş bekler, sonra metin moduna döner; böylece kullanıcı çizgiyi görebilir ve DOS istemi grafik ekranda kalmaz.
İki sürüm arasındaki hız farkı büyüktür. Doğrudan sürümde döngü gövdesi üç komuttur: bir bellek yazma, bir toplama ve LOOP. BIOS sürümünde her piksel için bir kesme çağrılır; kesme yordamı da koordinattan adresi kendisi hesaplar. emu8086'nın grafik desteği sınırlıdır: 0Ch hizmetiyle çizim yavaştır, A000h'a doğrudan yazma ise her sürümde görünmeyebilir. DOSBox gibi bir PC öykünücüsünde her iki sürüm de tam görünür.
İzlemeyi kısa tutmak için aşağıdaki program yalnız dört piksel çizer ve mod değiştirmez. Döngünün her turunda DI'nin 141h arttığı açıkça görülür.
org 100h
mov ax, 0A000h
mov es, ax
xor di, di ; (0,0) → ofset 0
mov al, 0Eh ; sarı
mov cx, 4 ; ilk 4 piksel
ciz: mov es:[di], al
add di, 141h ; 320 + 1
loop ciz
ret| Adım | Komut | AL | CX | DI | ES | Açıklama |
|---|---|---|---|---|---|---|
| 1 | mov ax, 0A000h | 00h | 0000h | 0000h | 0700h | kesim değeri AX üzerinden |
| 2 | mov es, ax | 00h | 0000h | 0000h | A000h | ES = A000h: mod 13h görüntü belleği |
| 3 | xor di, di | 00h | 0000h | 0000h | A000h | DI = 0: piksel (0, 0) |
| 4 | mov al, 0Eh | 0Eh | 0000h | 0000h | A000h | renk 0Eh (sarı) |
| 5 | mov cx, 4 | 0Eh | 0004h | 0000h | A000h | dört piksel |
| 6 | mov es:[di], al | 0Eh | 0004h | 0000h | A000h | A0000h ← 0Eh: piksel (0, 0) |
| 7 | add di, 141h | 0Eh | 0004h | 0141h | A000h | bir alt satır, bir sağ sütun |
| 8 | loop ciz | 0Eh | 0003h | 0141h | A000h | CX = 3 ≠ 0: ciz'e dön |
| 9 | mov es:[di], al | 0Eh | 0003h | 0141h | A000h | A0141h ← 0Eh: piksel (1, 1) |
| 12 | mov es:[di], al | 0Eh | 0002h | 0282h | A000h | A0282h ← 0Eh: piksel (2, 2) |
| 15 | mov es:[di], al | 0Eh | 0001h | 03C3h | A000h | A03C3h ← 0Eh: piksel (3, 3) |
| 16 | add di, 141h | 0Eh | 0001h | 0504h | A000h | DI = 0504h = (4, 4)'ün yeri |
| 17 | loop ciz | 0Eh | 0000h | 0504h | A000h | CX = 0: döngü biter |
| 18 | ret | 0Eh | 0000h | 0504h | A000h | program biter |
Tablodaki DI değerleri 0000h, 0141h, 0282h, 03C3h ve 0504h, 321'in katlarıdır: 0, 321, 642, 963 ve 1284. Her biri y × 320 + x biçiminde yazılınca x = y olduğu görülür; örneğin 963 = 3 × 320 + 3. Döngü bitince DI, çizilmemiş beşinci pikselin (4, 4) yerini gösterir. Fiziksel adresler A0000h, A0141h, A0282h ve A03C3h'tir.
Sunumdaki piksel adresi gezgini, ekranda tıklanan noktanın (x, y) koordinatını, bağıl konumunu ve fiziksel adresini hesaplar. Köşegen ve ters köşegen düğmeleri, DI'ye 141h ya da 13Fh ekleyen döngüyü canlandırır.
5.2.4INT 16h: klavye hizmetleri
5.2.4.1Tarama kodu ve ASCII
Bir tuşa basıldığında klavyenin içindeki denetleyici, tuşun klavyedeki yerini gösteren bir sayı gönderir. PC'de bu sayı 60h G/Ç portundan okunur ve kesme denetleyicisi üzerinden IRQ 1 donanım kesmesini doğurur. BIOS'un klavye kesme yordamı (INT 09h) bu sayıyı alır, Shift ve Caps Lock durumuna bakarak ASCII karşılığını bulur. Sonra ikisini birlikte bir sözcük olarak bellekteki klavye tamponuna yazar. Program tuşları bu tampondan INT 16h ile okur. Böylece program meşgulken basılan tuşlar kaybolmaz; tamponda sıra bekler.
Tarama kodu (scan code), klavyede basılan tuşun fiziksel konumunu gösteren koddur. Aynı tuş, Shift basılı olsa da olmasa da aynı tarama kodunu verir: 'a' ve 'A' için 1Eh. ASCII kodu ise tuşun o anki anlamını, yani üretilen karakteri gösterir: 'a' için 61h, 'A' için 41h.
| AH | Hizmet | Çıkış |
|---|---|---|
| 00h | tuş bekle ve oku | AH = tarama kodu, AL = ASCII; tuş tampondan silinir |
| 01h | tuş var mı? (beklemez) | ZF = 1: tuş yok · ZF = 0: AX = tuş; tuş tampondan silinmez |
| 02h | Shift durumları | AL bitleri: 0 sağ Shift, 1 sol Shift, 2 Ctrl, 3 Alt, 4 Scroll Lock, 5 Num Lock, 6 Caps Lock, 7 Insert |
AH = 00h, tamponda tuş yoksa bir tuşa basılana kadar bekler. Tuş gelince AH'ye tarama kodunu, AL'ye ASCII kodunu koyar ve tuşu tampondan siler. Tuş ekrana yansıtılmaz; ekranda bir şey görünmesi isteniyorsa program onu kendisi yazar. Tablo 5.2.16 bazı tuşların döndürdüğü değerleri listeler.
| Tuş | AH (tarama) | AL (ASCII) | Tuş | AH (tarama) | AL |
|---|---|---|---|---|---|
| a / A | 1Eh | 61h / 41h | ↑ / ↓ | 48h / 50h | 00h |
| 1 | 02h | 31h | ← / → | 4Bh / 4Dh | 00h |
| Enter | 1Ch | 0Dh | F1 … F10 | 3Bh … 44h | 00h |
| Esc | 01h | 1Bh | Backspace | 0Eh | 08h |
| Boşluk | 39h | 20h | Ctrl+C | 2Eh | 03h |
Ok tuşları, işlev tuşları, Home ve End gibi tuşların ASCII karşılığı yoktur. Bunlara genişletilmiş tuşlar denir ve INT 16h bunlar için AL = 00h döndürür. Program önce AL'ye bakar; AL sıfırsa tuşu AH'deki tarama kodundan tanır. F1 tuşu örneğin AH = 3Bh, AL = 00h verir. Ctrl ile basılan harfler ise ASCII'nin ilk 32 koduna düşer: Ctrl+A = 01h, Ctrl+C = 03h. Kodu, harfin kodunun düşük beş bitidir.
Program sonlarında sık görülen MOV AH, 0 · INT 16h ikilisinin görevi basittir. Program bir tuş bekler, böylece çıktı ekranı kapanmadan okunabilir. Sunumdaki klavye gezgini, basılan bir tuşun INT 16h/00h ile hangi AH ve AL değerlerini döndüreceğini gösterir.
5.2.4.2Kod izleme: tuş oku, büyük harfle yaz
Aşağıdaki program Enter'a basılana kadar tuş okur. Küçük harfleri büyüğe çevirip yazar, öteki karakterleri olduğu gibi yazar. Program INT 16h'nin yansıtma yapmadığını ve ASCII düzeninin bit 5 kuralını birlikte kullanır.
org 100h
oku:
mov ah, 0 ; tuş bekle
int 16h ; AH=tarama, AL=ASCII
cmp al, 0Dh ; Enter?
je bitti
cmp al, 'a'
jb yaz
cmp al, 'z'
ja yaz
sub al, 20h ; küçük → büyük
yaz:
mov ah, 0Eh
int 10h ; ekrana yaz
jmp oku
bitti:
retDöngü oku etiketinde başlar. INT 16h bir tuş bekler. CMP AL, 0Dh Enter'ı denetler; eşitse JE programı bitirir. Ardından iki karşılaştırma, AL'nin 'a'–'z' aralığında olup olmadığını sınar. JB ve JA işaretsiz karşılaştırma komutlarıdır: JB, CF = 1 iken; JA, CF = 0 ve ZF = 0 iken atlar. AL 'a'dan küçükse ya da 'z'den büyükse harf olmadığı için doğrudan yaz'a gidilir. Aralığın içindeyse SUB AL, 20h bit 5'i temizler. yaz kısmı karakteri teletype ile yazar ve döngü başına döner.
Kullanıcı sırayla Shift+o, k ve Enter tuşlarına basıyor. Tablo 5.2.17 önemli adımları verir; aynı turdaki benzer adımlar atlanmıştır.
| Adım | Komut | AX | CF | ZF | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|
| 1 | mov ah, 0 | 0000h | 0 | 0 | – | AH = 00h: tuş bekle ve oku |
| 2 | int 16h | 184Fh | 0 | 0 | – | Shift+o: AH = 18h (tarama), AL = 4Fh ('O') |
| 3 | cmp al, 0Dh | 184Fh | 0 | 0 | – | 4Fh − 0Dh: sonuç sıfır değil |
| 4 | je bitti | 184Fh | 0 | 0 | – | Enter değil, atlama yok |
| 5 | cmp al, 'a' | 184Fh | 1 | 0 | – | 4Fh < 61h: ödünç, CF = 1 |
| 6 | jb yaz | 184Fh | 1 | 0 | – | CF = 1: yaz'a atla |
| 7 | mov ah, 0Eh | 0E4Fh | 1 | 0 | – | AH = 0Eh; AL'de 'O' duruyor |
| 8 | int 10h | 0E4Fh | 1 | 0 | O | ekrana O |
| 9 | jmp oku | 0E4Fh | 1 | 0 | O | döngü başına |
| 11 | int 16h | 256Bh | 1 | 0 | O | k: AH = 25h, AL = 6Bh |
| 14 | cmp al, 'a' | 256Bh | 0 | 0 | O | 6Bh ≥ 61h: CF = 0 |
| 15 | jb yaz | 256Bh | 0 | 0 | O | atlama yok: küçük harf olabilir |
| 16 | cmp al, 'z' | 256Bh | 1 | 0 | O | 6Bh − 7Ah: ödünç, CF = 1, ZF = 0 |
| 17 | ja yaz | 256Bh | 1 | 0 | O | JA, CF = 0 ve ZF = 0 ister; atlamaz |
| 18 | sub al, 20h | 254Bh | 0 | 0 | O | 6Bh − 20h = 4Bh = 'K' |
| 20 | int 10h | 0E4Bh | 0 | 0 | OK | ekrana K |
| 23 | int 16h | 1C0Dh | 0 | 0 | OK | Enter: AH = 1Ch, AL = 0Dh |
| 24 | cmp al, 0Dh | 1C0Dh | 0 | 1 | OK | 0Dh − 0Dh = 0: ZF = 1 |
| 25 | je bitti | 1C0Dh | 0 | 1 | OK | bitti'ye atla |
| 26 | ret | 1C0Dh | 0 | 1 | OK | program biter |
İlk tuşta AL = 4Fh ('O') gelir. CMP AL, 'a' 4Fh − 61h hesaplar; sonuç negatiftir, ödünç gerekir ve CF = 1 olur. JB atlar: karakter küçük harf değildir ve olduğu gibi yazılır. İkinci tuşta AL = 6Bh ('k') gelir. 6Bh − 61h ödünç istemez, CF = 0 olur ve JB atlamaz. 6Bh − 7Ah ise ödünç ister: CF = 1, ZF = 0. JA'nın atlaması için hem CF hem ZF sıfır olmalıydı; atlamaz. Böylece AL'nin 61h ≤ AL ≤ 7Ah aralığında olduğu kesinleşir. SUB AL, 20h 6Bh'yi 4Bh'ye, yani 'K'ye çevirir. Enter ile gelen 0Dh, ilk karşılaştırmada ZF = 1 yapar ve program biter.
Tablonun AX sütununda bir ayrıntı daha görülür. Teletype çağrısından önce AH = 0Eh yapılır; döngü başında MOV AH, 0 yeniden AH'yi sıfırlar ama AL, son yazılan karakteri korur. INT 16h dönüşünde ise AH ile AL'nin ikisi de yeni tuşla değişir. Ekranda sonuçta OK görünür. Enter'ın kendisi yansıtılmadığı için imleç satırda kalır.
5.2.4.3Beklemeden yoklama
AH = 00h tuş gelene kadar programı durdurur. Bir oyun ya da animasyon ise tuş beklerken çalışmayı sürdürmek zorundadır. Bunun için AH = 01h kullanılır: hizmet hemen döner ve tuş olup olmadığını ZF ile bildirir. ZF = 1 ise tamponda tuş yoktur. ZF = 0 ise tuş vardır ve AX'te durur, ama tampondan silinmez. Program tuşu gerçekten almak için ardından AH = 00h çağırır. Bir aygıtın durumunu döngü içinde tekrar tekrar sormaya yoklama (polling) denir.
org 100h
xor dx, dx ; iş sayacı
bekle:
inc dx ; arka plan işi
mov ah, 01h ; tuş var mı?
int 16h ; ZF=1 → yok
jz bekle
mov ah, 00h ; tuşu tampondan al
int 16h
retDX, bekleme sırasında yapılan işi temsil eder; her turda bir artar. Gerçek bir programda burada bir animasyon karesi çizilir ya da bir hesap ilerletilir. İzlemede ilk iki yoklamada tuş yoktur, üçüncüsünde kullanıcı x tuşuna basmıştır.
| Adım | Komut | AX | DX | ZF | Açıklama |
|---|---|---|---|---|---|
| 1 | xor dx, dx | 0000h | 0000h | 1 | iş sayacı sıfırlanır |
| 2 | inc dx | 0000h | 0001h | 0 | arka plan işi: 1 |
| 3 | mov ah, 01h | 0100h | 0001h | 0 | AH = 01h: tuş var mı? |
| 4 | int 16h | 0100h | 0001h | 1 | tampon boş: ZF = 1 |
| 5 | jz bekle | 0100h | 0001h | 1 | ZF = 1: bekle'ye dön |
| 6 | inc dx | 0100h | 0002h | 0 | arka plan işi: 2 |
| 8 | int 16h | 0100h | 0002h | 1 | yine tuş yok |
| 10 | inc dx | 0100h | 0003h | 0 | arka plan işi: 3 |
| 12 | int 16h | 2D78h | 0003h | 0 | x var: ZF = 0, AX = 2D78h; tuş tamponda kalır |
| 13 | jz bekle | 2D78h | 0003h | 0 | ZF = 0: döngüden çık |
| 14 | mov ah, 00h | 0078h | 0003h | 0 | AH = 00h: tuşu al |
| 15 | int 16h | 2D78h | 0003h | 0 | aynı tuş okunur ve tampondan silinir |
| 16 | ret | 2D78h | 0003h | 0 | program biter |
İlk iki turda INT 16h ZF = 1 döndürür ve JZ döngüyü sürdürür. Program donmaz: her turda DX artar. Üçüncü turda tuş gelmiştir. INT 16h ZF = 0 yapar ve AX'e 2D78h koyar: tarama kodu 2Dh, ASCII 78h ('x'). Tuş tamponda kalmaya devam eder. JZ atlamaz, döngüden çıkılır. AH = 00h aynı tuşu okur ve bu kez tampondan siler; AX yine 2D78h'dir. Programın sonunda DX = 3, yani tuş beklenirken arka plan işi üç kez yapılmıştır.
01h ile tuşu görüp 00h ile almamak. 01h tuşu tampondan silmediği için döngünün sonraki turunda aynı tuş yine “var” görünür; program tek bir tuşa sonsuz kez tepki verir. Tuşa yanıt verildikten sonra AH = 00h ile tampon boşaltılır.
5.2.5INT 21h: DOS karakter ve dizgi hizmetleri
5.2.5.1Sık kullanılan hizmetler
INT 21h, DOS'un ana hizmet kesmesidir. Yüzlerce hizmetin içinden karakter ve dizgi G/Ç'si, tarih, saat ve program sonlandırma en sık kullanılanlardır. Tablo 5.2.19 bunları özetler.
| AH | Hizmet | Giriş | Çıkış |
|---|---|---|---|
| 01h | karakter oku ve yansıt | – | AL = karakter |
| 02h | karakter yaz | DL = karakter | AL = DL |
| 07h / 08h | karakter oku, yansıtmadan | – | AL (08h Ctrl+C'yi denetler) |
| 09h | dizgi yaz | DS:DX → '$' ile biten dizgi | AL = 24h |
| 0Ah | tamponlu satır oku | DS:DX → tampon | [tampon+1] = sayı, tampon+2 = metin |
| 2Ah | tarihi al | – | CX = yıl, DH = ay, DL = gün, AL = haftanın günü (0 = Pazar) |
| 2Ch | saati al | – | CH = saat, CL = dakika, DH = saniye, DL = salise |
| 2Bh / 2Dh | tarihi / saati ayarla | 2Ah / 2Ch ile aynı yazmaçlar | AL = 00h başarılı |
| 4Ch | programı sonlandır | AL = çıkış kodu | (dönmez) |
DOS hizmetlerinin BIOS hizmetlerinden önemli bir farkı, G/Ç yönlendirmesine uymalarıdır. Program program > cikti.txt biçiminde çalıştırılırsa 02h ve 09h ile yazılan her şey ekran yerine dosyaya gider. BIOS'un INT 10h çıktısı ise her zaman ekrana gider; DOS onu göremez. Benzer biçimde 01h ve 0Ah, girdiyi bir dosyadan da alabilir.
5.2.5.2INT 10h/0Eh mi, INT 21h/02h mi?
Ekrana tek karakter yazan iki hizmet çok benzer görünür. İkisi de karakteri imlecin olduğu yere yazar ve imleci ilerletir; CR, LF gibi denetim karakterlerini yorumlar. Farkları, hangi katmanda çalıştıklarından gelir. Tablo 5.2.20 karşılaştırır.
| Özellik | BIOS · INT 10h, AH = 0Eh | DOS · INT 21h, AH = 02h |
|---|---|---|
| Karakter | AL'de | DL'de |
| Gereken yazılım | yalnız video BIOS'u; açılış (boot) kodunda da çalışır | DOS yüklü olmalı |
| Yönlendirme | yok; hep ekrana | var; dosyaya, yazıcıya |
| Renk | grafik modda BL ile | yok |
| Dönüşte AL | korunur | AL = DL |
| Ctrl+Break denetimi | yok | var |
Seçim, programın hangi ortamda çalışacağına bağlıdır. Bir önyükleme yükleyicisi DOS'tan önce çalıştığı için yalnız BIOS'u kullanabilir. Çıktısı bir dosyaya kaydedilecek bir araç ise DOS hizmetini seçmelidir. Aynı programda ikisi karıştırılabilir; ikisi de BIOS'un tuttuğu aynı imleç konumunu kullanır.
5.2.5.3Kod izleme: karakter oku ve yaz
Aşağıdaki program klavyeden bir karakter okur, yeni bir satıra geçer ve okunan karakterden sonraki harfi yazar. Kısa olmasına karşın AL'nin hizmetler arasında nasıl bozulduğunu açıkça gösterir.
org 100h
mov ah, 01h ; oku + yansıt
int 21h ; AL = karakter
mov bl, al ; sakla
mov ah, 02h ; karakter yaz
mov dl, 0Dh ; CR: satır başı
int 21h
mov dl, 0Ah ; LF: alt satır
int 21h
inc bl ; sonraki harf
mov dl, bl
int 21h
ret| Adım | Komut | AX | BX | DX | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|
| 1 | mov ah, 01h | 0100h | 0000h | 0000h | – | AH = 01h: oku ve yansıt |
| 2 | int 21h | 016Bh | 0000h | 0000h | k | k: AL = 6Bh; ekranda k |
| 3 | mov bl, al | 016Bh | 006Bh | 0000h | k | okunan karakter BL'de saklanır |
| 4 | mov ah, 02h | 026Bh | 006Bh | 0000h | k | AH = 02h: DL'yi yaz |
| 5 | mov dl, 0Dh | 026Bh | 006Bh | 000Dh | k | DL = 0Dh (CR) |
| 6 | int 21h | 020Dh | 006Bh | 000Dh | k⏎ | imleç satır başına; AL = 0Dh |
| 7 | mov dl, 0Ah | 020Dh | 006Bh | 000Ah | k⏎ | DL = 0Ah (LF) |
| 8 | int 21h | 020Ah | 006Bh | 000Ah | k↵ | imleç alt satıra; AL = 0Ah |
| 9 | inc bl | 020Ah | 006Ch | 000Ah | k↵ | BL = 6Ch ('l') |
| 10 | mov dl, bl | 020Ah | 006Ch | 006Ch | k↵ | DL = 'l' |
| 11 | int 21h | 026Ch | 006Ch | 006Ch | k↵l | ekrana l; AL = 6Ch |
| 12 | ret | 026Ch | 006Ch | 006Ch | k↵l | program biter |
AH = 01h bir tuş bekler ve tuşu ekrana yansıtır; kullanıcı k bastığında ekranda k görünür ve AL = 6Bh olur. Okunan değer hemen BL'ye kopyalanır, çünkü sonraki INT 21h çağrıları AL'yi değiştirecektir. Gerçekten de CR yazıldıktan sonra AL = 0Dh, LF yazıldıktan sonra AL = 0Ah olur. 02h hizmeti dönüşte AL'ye DL'yi koyar. AH ise 02h olarak kalır; bu yüzden üç çağrı için bir kez yüklenmesi yeter. CR imleci satır başına, LF bir alt satıra götürür. INC BL 6Bh'yi 6Ch'ye, 'k'yi 'l'ye çevirir ve son çağrı bu harfi yeni satıra yazar. Ekranın son durumu iki satırdır: üstte yansıtılan k, altta l.
5.2.5.4Kod izleme: dizgi yazdırma
AH = 09h, DS:DX'in gösterdiği dizgiyi '$' (24h) karakterini görene kadar yazar. '$' sonlandırıcıdır; kendisi yazılmaz. Dizginin içindeki 0Dh ve 0Ah satırı bitirir, yani denetim karakterleri burada da yorumlanır.
'$' ile biten dizgi, DOS'un 09h hizmetinin beklediği biçimdir: karakterler bellekte art arda durur ve ilk 24h baytında dizgi biter. Uzunluk ayrıca verilmez. Hizmet dönüşte AL'yi 24h yapar.
org 100h
mov dx, offset msg1 ; DS:DX → dizgi
mov ah, 09h
int 21h
mov dx, offset msg2
int 21h ; AH hâlâ 09h
ret
msg1 db 'Merhaba, 8086!', 0Dh, 0Ah, '$'
msg2 db 'Gule gule$'Kod kısmı 13 bayttır (0100h–010Ch). msg1 bu yüzden 010Dh'de başlar. msg1 14 karakter, CR, LF ve '$' olmak üzere 17 bayttır; msg2 010Dh + 17 = 011Eh'dedir. OFFSET işleci, değişkenin içeriğini değil bağıl konumunu verir.
| Adım | Komut | AX | DX | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|
| 1 | mov dx, offset msg1 | 0000h | 010Dh | – | DS:DX → msg1 (010Dh) |
| 2 | mov ah, 09h | 0900h | 010Dh | – | AH = 09h |
| 3 | int 21h | 0924h | 010Dh | Merhaba, 8086!↵ | '$'a kadar yazılır; AL = 24h |
| 4 | mov dx, offset msg2 | 0924h | 011Eh | Merhaba, 8086!↵ | DX → msg2 (011Eh) |
| 5 | int 21h | 0924h | 011Eh | Merhaba, 8086!↵Gule gule | AH hâlâ 09h: ikinci dizgi |
| 6 | ret | 0924h | 011Eh | Merhaba, 8086!↵Gule gule | program biter |
İlk çağrı Merhaba, 8086! yazar ve CR LF ile yeni satıra geçer. AL = 24h olur. İkinci çağrıdan önce yalnız DX değiştirilir; AH hâlâ 09h'dir. Yine de her çağrıdan önce AH'yi yüklemek, programa sonradan eklenen bir satırın AH'yi bozma riskine karşı iyi bir alışkanlıktır. Çıktı iki satırdır. '$' karakterinin kendisi bu hizmetle yazdırılamaz; onu yazmak için 02h hizmeti ve DL = 24h kullanılır.
Dizginin sonuna '$' koymayı unutmak. 09h bellekte ilk 24h baytını bulana kadar ne varsa yazar: programın kodu, başka değişkenler, rastgele baytlar. Ekran çöple dolar, hatta denetim karakterleri yüzünden zil çalar. Tersi de olur: 'Fiyat: 5$ TL$' dizgisi yalnız Fiyat: 5 olarak yazılır, çünkü ilk '$' dizgiyi bitirir.
5.2.5.5Tamponlu satır girişi
Kullanıcıdan bir ad ya da bir sayı almak, tuşları tek tek okumaktan fazlasını gerektirir. Kullanıcı yanlış yazınca Backspace ile siler, Enter'a basınca satırı bitirir. AH = 0Ah bu düzenlemeyi DOS'a yaptırır. Program yalnız bir tampon hazırlar ve adresini DS:DX'e koyar. DOS, Enter'a basılana kadar tuşları okur, yansıtır, Backspace ve Esc ile düzeltmeye izin verir. Bu sürede program çalışmaz; satır bitince çağrı döner.
0Ah tamponu üç kısımdan oluşur. Bayt 0'a program kapasiteyi yazar: Enter dahil en çok kaç karakter alınacağı. Bayt 1'e DOS okunan karakter sayısını yazar (Enter sayılmaz). Bayt 2'den başlayarak metin gelir ve sonuna Enter'ın kodu 0Dh eklenir. Kapasite 0 olamaz.
Şekil 5.2.12, tampon db 10, ?, 10 dup(?) tanımlı bir tampona Ali yazılıp Enter'a basıldıktan sonraki durumu gösterir. Bayt 0 = 0Ah (10 karakter), bayt 1 = 03h, sonra 'A', 'l', 'i' ve 0Dh. Metin '$' ile bitmez; 09h ile yazdırmak için program 0Dh'nin yerine '$' koyar. Tampon dolduğunda DOS fazla tuşları kabul etmez ve zil çalar; yalnız Enter ve Backspace çalışmaya devam eder.
Aşağıdaki program kullanıcının adını okur ve ona selam verir.
org 100h
mov dx, offset tampon
mov ah, 0Ah ; tamponlu giriş
int 21h
mov bl, [tampon+1] ; okunan sayı
mov bh, 0
mov byte ptr tampon[bx+2], '$'
mov dx, offset selam
mov ah, 09h
int 21h
lea dx, [tampon+2]
int 21h
ret
tampon db 10, ?, 10 dup(?)
selam db 0Dh, 0Ah, 'Merhaba $'| Adım | Komut | AX | BX | DX | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|
| 1 | mov dx, offset tampon | 0000h | 0000h | 011Fh | – | DS:DX → tampon (011Fh) |
| 2 | mov ah, 0Ah | 0A00h | 0000h | 011Fh | – | AH = 0Ah: satır oku |
| 3 | int 21h | 0A00h | 0000h | 011Fh | Ali⏎ | tampon = 0Ah, 03h, 'A', 'l', 'i', 0Dh |
| 4 | mov bl, [tampon+1] | 0A00h | 0003h | 011Fh | Ali⏎ | BL = [0120h] = 3 |
| 5 | mov bh, 0 | 0A00h | 0003h | 011Fh | Ali⏎ | BX = 0003h |
| 6 | mov byte ptr tampon[bx+2], '$' | 0A00h | 0003h | 011Fh | Ali⏎ | [011Fh + 3 + 2] = [0124h] ← '$' |
| 7 | mov dx, offset selam | 0A00h | 0003h | 012Bh | Ali⏎ | DX → selam (012Bh) |
| 8 | mov ah, 09h | 0900h | 0003h | 012Bh | Ali⏎ | AH = 09h |
| 9 | int 21h | 0924h | 0003h | 012Bh | Ali⏎↵Merhaba | CR LF ve Merhaba yazılır |
| 10 | lea dx, [tampon+2] | 0924h | 0003h | 0121h | Ali⏎↵Merhaba | DX = 0121h: metnin başı |
| 11 | int 21h | 0924h | 0003h | 0121h | Ali⏎↵Merhaba Ali | Ali yazılır |
| 12 | ret | 0924h | 0003h | 0121h | Ali⏎↵Merhaba Ali | program biter |
Programın kodu 31 bayttır (0100h–011Eh). emu8086, doğrudan adresli LEA DX, [tampon+2] komutunu MOV DX, OFFSET tampon+2 ile aynı üç baytlık koda (BA 21 01) derler; tampon bu yüzden 011Fh'de, selam 012Bh'de başlar. Çağrı dönünce tampon 011Fh'den itibaren 0A 03 41 6C 69 0D baytlarını tutar. MOV BL, [tampon+1] okunan sayıyı, 3'ü alır. BH sıfırlanır, çünkü sayı adres hesabında BX olarak kullanılacaktır. tampon[bx+2] adresi 011Fh + 3 + 2 = 0124h'tür; tam olarak 0Dh'nin bulunduğu bayt. Oraya '$' yazılır ve metin 09h ile yazılabilir hâle gelir. BYTE PTR belirteci burada açıklık içindir. tampon DB ile tanımlandığı için assembler yazmanın bir bayt olduğunu zaten bilir; değişken adı geçmeyen [BX+2] gibi bir adreste ise belirteç zorunludur.
Sonra selam yazılır: başta CR LF olduğu için yeni satıra geçilir ve Merhaba basılır. Enter'ın kendisi yalnız CR yansıttığından imleç satır başındaydı; LF onu alt satıra indirir. LEA DX, [tampon+2] metnin başını, 0121h'yi DX'e yükler. AH hâlâ 09h olduğundan son çağrı Ali yazar. Ekranda Merhaba Ali görünür.
tampon db 6, ?, 6 dup(?) tanımlı bir tampona kullanıcı Mikro12 yazıp Enter'a basıyor. Kapasite Enter dahil 6 olduğundan en çok 5 karakter alınır. 'M', 'i', 'k', 'r', 'o' kabul edilir; '1' ve '2' tuşlarında zil çalar. Enter gelince tampon 06 05 4D 69 6B 72 6F 0D olur. Okunan sayı 5'tir; '$' tampon + 5 + 2 = tampon + 7 adresine yazılır ve ekrana yalnız Mikro basılır.
Tamponun ilk baytını ayarlamamak ya da metni tampon+0'dan okumak. Kapasite 0 kalırsa hizmet beklenmedik biçimde davranır. Metin her zaman tampon+2'den başlar; tampon+0 ve tampon+1 sayılardır ve ekrana yazılırsa anlamsız karakterler çıkar.
5.2.6Tarih ve saat
5.2.6.1AH = 2Ah ve AH = 2Ch
DOS, sistemin tarihini ve saatini iki hizmetle verir. AH = 2Ah tarihi, AH = 2Ch saati döndürür. Tablo 5.2.24 dönüş yazmaçlarını gösterir. Değerlerin hepsi ikili sayıdır. Saat 14 ise CH = 0Eh, dakika 35 ise CL = 23h gelir. Yıl 16 bitlik CX'e sığar: 2026 = 07EAh.
| Yazmaç | AH = 2Ah (tarih) | AH = 2Ch (saat) |
|---|---|---|
| CX / CH | CX = yıl (ör. 07EAh = 2026) | CH = saat (0–23) |
| CL | (CX'in parçası) | CL = dakika (0–59) |
| DH | ay (1–12) | saniye (0–59) |
| DL | gün (1–31) | salise (0–99) |
| AL | haftanın günü (0 = Pazar … 6 = Cumartesi) | – |
İkili değerleri ekrana yazmak için her sayı onluk basamaklarına ayrılır. 0–99 arasındaki bir sayı için en kısa yol AAM komutudur. AAM, AL'yi 10'a böler; bölümü AH'ye, kalanı AL'ye yazar. 14 için AH = 1, AL = 4 olur. Ardından iki basamağa 30h eklenir ve ASCII rakamlar elde edilir. Yıl gibi 99'dan büyük sayılar için 10'a tekrarlı bölme kullanılır. BIOS'un INT 1Ah/02h hizmeti ise saati ikili değil, BCD olarak verir ve orada AAM kullanılmaz.
AL = 23h (35) iken AAM çalışır: 35 ÷ 10 = 3, kalan 5. AH = 03h, AL = 05h, yani AX = 0305h. ADD AX, 3030h iki baytı birden ASCII'ye çevirir: AX = 3335h, AH = '3', AL = '5'. Önce AH, sonra AL yazılınca ekranda 35 görünür. AL = 07h için AX = 0007h → 3037h, ekranda 07: AAM tek basamaklı değerlere baştaki sıfırı kendiliğinden ekler.
5.2.6.2Kod izleme: gün adını yazdırma
Haftanın günü AL'de 0–6 arasında bir sayı olarak gelir. Bunu bir ada çevirmenin doğal yolu bir arama tablosudur: günlerin adları bellekte eşit uzunlukta art arda dizilir ve AL, tablodaki konuma çevrilir. Aşağıdaki programda her ad '$' dahil 4 bayttır; bu yüzden konum AL × 4'tür.
org 100h
mov ah, 2Ah
int 21h ; AL = 0…6
mov ah, 0
mov bl, 4
mul bl ; AX = AL × 4
mov dx, offset gunler
add dx, ax
mov ah, 09h
int 21h
ret
gunler db 'Paz$Pzt$Sal$Car$'
db 'Per$Cum$Cmt$'Tarih sistem saatinden gelir; izleme 7 Ocak 2026 Çarşamba içindir. INT 21h dönüşünde CX = 07EAh (2026), DH = 01h (Ocak), DL = 07h ve AL = 3 (Çarşamba) olur. DX bu anda 0107h'dir. MOV AH, 0 AX'i 0003h yapar. MUL BL AL ile BL'yi çarpar ve 16 bitlik sonucu AX'e yazar: 3 × 4 = 12 = 000Ch. Bu, Car$ adının tablonun başından uzaklığıdır.
MOV DX, OFFSET gunler DX'teki tarihi siler ve tablonun bağıl konumunu, 0114h'yi yükler. Tarih daha sonra gerekecek olsaydı bu satırdan önce saklanmalıydı. ADD DX, AX 0114h + 000Ch = 0120h verir: Car$'ın ilk baytı. AH = 09h ile ekrana Car yazılır.
| Adım | Komut | AX | BX | CX | DX | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|---|
| 1 | mov ah, 2Ah | 2A00h | 0000h | 0000h | 0000h | – | AH = 2Ah: tarihi al |
| 2 | int 21h | 2A03h | 0000h | 07EAh | 0107h | – | CX = 07EAh (2026), DH = 01h (ay), DL = 07h (gün), AL = 3 (Çarşamba) |
| 3 | mov ah, 0 | 0003h | 0000h | 07EAh | 0107h | – | AX = 0003h |
| 4 | mov bl, 4 | 0003h | 0004h | 07EAh | 0107h | – | her ad 4 bayt |
| 5 | mul bl | 000Ch | 0004h | 07EAh | 0107h | – | AX = 3 × 4 = 12 = 000Ch |
| 6 | mov dx, offset gunler | 000Ch | 0004h | 07EAh | 0114h | – | DX = gunler = 0114h; tarih silindi |
| 7 | add dx, ax | 000Ch | 0004h | 07EAh | 0120h | – | DX = 0120h: Car$ |
| 8 | mov ah, 09h | 090Ch | 0004h | 07EAh | 0120h | – | AH = 09h |
| 9 | int 21h | 0924h | 0004h | 07EAh | 0120h | Car | ekrana Car |
| 10 | ret | 0924h | 0004h | 07EAh | 0120h | Car | program biter |
ADD DX, AX sonrası: DX = 0120h, gunler tablosunun +12. baytını, yani Car$'ı gösterir.Kod kısmı 20 bayttır, bu yüzden gunler 0114h'de başlar. Komutların uzunlukları: MOV AH, imm 2, INT 2, MOV BL, imm 2, MUL BL 2, MOV DX, imm 3, ADD DX, AX 2, RET 1 bayttır. Çarpma yerine iki kez sola kaydırma da kullanılabilirdi (SHL AX, 1 iki kez), çünkü 4 ikinin kuvvetidir. 8086'da MUL 70–77 saat turu sürer, iki SHL ise yalnız 4 tur.
MOV AH, 0 satırını atlamak. Bu programda zarar vermez, çünkü MUL BL AX'in tamamını yeniden yazar. Ama çarpma iki SHL AX, 1 ile yapılsaydı AH'de kalan 2Ah da kayardı: AX = 2A03h → A80Ch. DX = 0114h + A80Ch = A920h olur ve 09h bellekte alakasız bir yeri yazar. Tablo konumu hesaplanırken AX'in yüksek yarısı mutlaka sıfırlanmalıdır.
5.2.6.3Kod izleme: saati yazdırma
Saati SS:DD biçiminde yazmak için iki sayı aynı yolla yazdırılır. Tekrarlanan kısım bir yordama alınır: yaz2, AL'deki 0–99 arasındaki sayıyı iki basamak olarak yazar.
org 100h
mov ah, 2Ch ; sistem saatini al
int 21h ; CH=saat CL=dakika
mov al, ch
call yaz2
mov dl, ':'
mov ah, 02h
int 21h
mov al, cl
call yaz2
ret
yaz2: ; AL (0-99) → 2 hane
aam ; AH=onlar AL=birler
add ax, 3030h ; ASCII
mov bx, ax
mov dl, bh
mov ah, 02h
int 21h
mov dl, bl
int 21h
retİzleme saat 14:35:07,42 içindir. INT 21h dönüşünde CX = 0E23h (CH = 14, CL = 35) ve DX = 072Ah'dir (DH = 7 saniye, DL = 42 salise). CALL yaz2 dönüş adresini, yani call'dan sonraki komutun adresi 0109h'yi yığına iter; SP FFFEh'den FFFCh'ye iner. Yordamın içinde AAM 14'ü 1 ve 4'e ayırır, ADD AX, 3030h ASCII'ye çevirir.
MOV BX, AX satırı yordamın kilit noktasıdır. İki basamak AH ve AL'dedir, ama ilk INT 21h/02h çağrısı AL'ye DL'yi koyacak ve birler basamağını silecektir. Bu yüzden ikisi de BX'e kopyalanır ve DL'ye BH ile BL'den alınır. CL'deki dakika ise hiçbir çağrıda bozulmaz: yordam CX'e dokunmaz, 02h hizmeti de CX'i değiştirmez. Dakika MOV AL, CL ile güvenle alınır.
| Adım | Komut | AX | BX | CX | DX | SP | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|---|---|
| 1 | mov ah, 2Ch | 2C00h | 0000h | 0000h | 0000h | FFFEh | – | AH = 2Ch: saati al |
| 2 | int 21h | 2C00h | 0000h | 0E23h | 072Ah | FFFEh | – | CH = 0Eh (14), CL = 23h (35), DH = 07h, DL = 2Ah (42) |
| 3 | mov al, ch | 2C0Eh | 0000h | 0E23h | 072Ah | FFFEh | – | AL = saat |
| 4 | call yaz2 | 2C0Eh | 0000h | 0E23h | 072Ah | FFFCh | – | dönüş adresi 0109h yığında |
| 5 | aam | 0104h | 0000h | 0E23h | 072Ah | FFFCh | – | 14 = 1 × 10 + 4: AH = 1, AL = 4 |
| 6 | add ax, 3030h | 3134h | 0000h | 0E23h | 072Ah | FFFCh | – | iki basamak ASCII'ye: '1', '4' |
| 7 | mov bx, ax | 3134h | 3134h | 0E23h | 072Ah | FFFCh | – | BX'te saklanır; 02h AL'yi bozar |
| 8 | mov dl, bh | 3134h | 3134h | 0E23h | 0731h | FFFCh | – | DL = '1' |
| 9 | mov ah, 02h | 0234h | 3134h | 0E23h | 0731h | FFFCh | – | AH = 02h |
| 10 | int 21h | 0231h | 3134h | 0E23h | 0731h | FFFCh | 1 | ekrana 1; AL = 31h |
| 11 | mov dl, bl | 0231h | 3134h | 0E23h | 0734h | FFFCh | 1 | DL = '4' |
| 12 | int 21h | 0234h | 3134h | 0E23h | 0734h | FFFCh | 14 | ekrana 4 |
| 13 | ret | 0234h | 3134h | 0E23h | 0734h | FFFEh | 14 | 0109h'ye dönüş |
| 14 | mov dl, ':' | 0234h | 3134h | 0E23h | 073Ah | FFFEh | 14 | DL = ':' |
| 16 | int 21h | 023Ah | 3134h | 0E23h | 073Ah | FFFEh | 14: | ekrana : |
| 17 | mov al, cl | 0223h | 3134h | 0E23h | 073Ah | FFFEh | 14: | AL = dakika = 23h; CL bozulmadı |
| 18 | call yaz2 | 0223h | 3134h | 0E23h | 073Ah | FFFCh | 14: | dönüş adresi 0114h |
| 19 | aam | 0305h | 3134h | 0E23h | 073Ah | FFFCh | 14: | 35 = 3 × 10 + 5 |
| 20 | add ax, 3030h | 3335h | 3134h | 0E23h | 073Ah | FFFCh | 14: | '3', '5' |
| 24 | int 21h | 0233h | 3335h | 0E23h | 0733h | FFFCh | 14:3 | ekrana 3 |
| 26 | int 21h | 0235h | 3335h | 0E23h | 0735h | FFFCh | 14:35 | ekrana 5 |
| 27 | ret | 0235h | 3335h | 0E23h | 0735h | FFFEh | 14:35 | 0114h'ye dönüş |
| 28 | ret | 0235h | 3335h | 0E23h | 0735h | 0000h | 14:35 | yığından 0000h; SP = 0000h |
| 29 | INT 20h (PSP:0000h) | 0235h | 3335h | 0E23h | 0735h | 0000h | 14:35 | INT 20h programı bitirir |
Son iki satır programın nasıl bittiğini gösterir. Yordamdan dönen RET (adım 27) yığından 0114h'yi alır ve SP'yi FFFEh'ye geri getirir. Ana programın RET'i (adım 28) ise yığının en üstündeki 0000h'yi IP'ye yükler ve SP = 0000h olur. 0000h, PSP'nin başıdır ve orada DOS'un koyduğu INT 20h komutu programı bitirir. Ekranda 14:35 kalır.
5.2.7INT 1Ah ve BIOS veri alanı
5.2.7.1Tık sayacı ve gerçek zamanlı saat
PC'de zamanı iki ayrı donanım tutar. Birincisi 8253/8254 programlanabilir zamanlayıcısıdır. Kanal 0, 1 193 182 Hz'lik bir saati 65 536'ya bölerek saniyede yaklaşık 18,2 kez IRQ 0 kesmesini üretir. BIOS'un bu kesmeye bağlı yordamı (INT 08h) her seferinde bellekteki bir sayacı bir artırır. Bu sayaca tık sayacı denir; gece yarısından beri geçen tık sayısını tutar. Sayaç bellekte olduğu için bilgisayar kapanınca kaybolur.
İkincisi, AT ve sonraki bilgisayarlarda bulunan gerçek zamanlı saattir (real-time clock, RTC). RTC, pille beslenen CMOS bir yongadır ve bilgisayar kapalıyken de çalışır. Saati, dakikayı, saniyeyi ve tarihi kendi yazmaçlarında BCD olarak tutar; 70h ve 71h G/Ç portları üzerinden okunur. Açılışta DOS saatini RTC'den alır, sonra tık sayacıyla ilerletir. INT 1Ah her iki saate de BIOS arayüzü sunar.
| AH | İşlev | Dönüş |
|---|---|---|
| 00h | tık sayacını oku | CX:DX = gece yarısından beri tık sayısı, AL = gün döndü bayrağı |
| 02h | RTC saatini oku | CH = saat, CL = dakika, DH = saniye (BCD), DL = yaz saati; CF = 1: hata |
| 04h | RTC tarihini oku | CH = yüzyıl, CL = yıl, DH = ay, DL = gün (BCD); CF = 1: hata |
Paketli BCD (packed binary-coded decimal), bir bayta iki onluk basamak koyan gösterimdir: yüksek dört bit (yüksek nibble) onlar basamağını, düşük dört bit birler basamağını tutar. Dakika 35, paketli BCD'de 35h = 0011 0101b olarak saklanır; ikili gösterimde ise 23h = 0010 0011b'dir.
BCD'nin yararı, onaltılık yazılışın doğrudan onluk değeri göstermesidir: 35h “otuz beş” okunur. Ekrana yazmak için bölme gerekmez; iki nibble ayrılır ve her birine 30h eklenir. Yüksek nibble dört bit sağa kaydırılarak, düşük nibble 0Fh ile maskelenerek ayrılır. 8086'da 1'den büyük sabit kaydırma yoktur; kaydırma sayısı CL'de verilir.
| Adım | İşlem | Sonuç |
|---|---|---|
| 1 | 35h = 0011 0101b | yüksek nibble 3, düşük nibble 5 |
| 2 | shr dl, cl (CL = 4) | 0000 0011b = 03h |
| 3 | and dl, 0Fh | 0000 0101b = 05h |
| 4 | +30h | '3' = 33h, '5' = 35h |
Aynı dakikayı INT 21h/2Ch ikili verir: CL = 23h. Orada AAM ya da 10'a bölme gerekir. İki yöntem karıştırılırsa ekrana yanlış sayı yazılır, ama hata ancak 10 ve üstündeki değerlerde görünür, çünkü 0–9 arasında BCD ile ikili aynıdır.
Saat 14:23. RTC dakikayı CL = 23h (BCD) verir. Bu değer AAM kullanan yaz2 yordamına gönderilirse AAM onu ikili 35 sayar ve ekrana 35 yazılır. DOS ise dakikayı CL = 17h (ikili 23) verir. Bu değer BCD yordamına gönderilirse nibble'lar 1 ve 7 olarak ayrılır, ekrana 17 yazılır. Doğrusu, RTC değerini SHR/AND ile, DOS değerini AAM ile yazdırmaktır.
emu8086'nın desteklediği kesmeler arasında INT 1Ah için yalnız 00h (tık sayacı) bulunur. 02h hizmeti gerçek DOS ortamında ya da DOSBox'ta çalışır; emu8086'da saat INT 21h/2Ch ile okunur.
5.2.7.2Kod izleme: RTC saatini yazdırma
Aşağıdaki program RTC saatini SS:DD:ss biçiminde yazar. İki yordam girişi paylaşır: ikinokta önce ':' yazar, sonra hiçbir atlama olmadan bcdyaz'a düşer. Saat için doğrudan bcdyaz, dakika ve saniye için ikinokta çağrılır.
org 100h
mov ah, 02h
int 1Ah ; CH=saat CL=dk DH=sn
jc son ; CF=1: saat okunamadı
mov bl, cl ; dakikayı sakla
mov cl, 4 ; SHR kaydırma sayısı
mov bh, ch
call bcdyaz ; "14"
mov bh, bl
call ikinokta ; ":35"
mov bh, dh
call ikinokta ; ":07"
son: ret
ikinokta: mov dl, ':'
mov ah, 02h
int 21h
bcdyaz: ; BH = paketli BCD
mov dl, bh
shr dl, cl ; üst hane
add dl, 30h ; ASCII rakam
mov ah, 02h
int 21h
mov dl, bh
and dl, 0Fh ; alt hane
add dl, 30h
int 21h
retProgram önce CF'ye bakar. RTC çalışmıyorsa ya da o an güncelleniyorsa hizmet CF = 1 döndürür; program yazdırmadan biter. İzlemede saat 14:35:07'dir ve CF = 0'dır. Dönüşte CH = 14h, CL = 35h, DH = 07h gelir; DL = 00h yaz saatinin kapalı olduğunu söyler.
Yazmaç kullanımı dikkatle planlanmıştır. CL'ye kaydırma sayısı 4 yazılacağından dakika önce BL'ye kopyalanır. Yordam değeri BH'de bekler; BH'ye sırayla saat (CH), dakika (BL) ve saniye (DH) konur. DL, karakter yazmak için gereklidir; ama saniye DH'de durduğu için DL'nin bozulması sorun olmaz. INT 21h/02h, BX'e, CX'e ve DH'ye dokunmaz.
| Adım | Komut | AX | BX | CX | DX | SP | CF | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|---|---|---|
| 1 | mov ah, 02h | 0200h | 0000h | 0000h | 0000h | FFFEh | 0 | – | AH = 02h: RTC saatini oku |
| 2 | int 1Ah | 0200h | 0000h | 1435h | 0700h | FFFEh | 0 | – | CH = 14h, CL = 35h, DH = 07h (paketli BCD); DL = 00h |
| 3 | jc son | 0200h | 0000h | 1435h | 0700h | FFFEh | 0 | – | CF = 0: atlama yok |
| 4 | mov bl, cl | 0200h | 0035h | 1435h | 0700h | FFFEh | 0 | – | dakika BL'de saklanır |
| 5 | mov cl, 4 | 0200h | 0035h | 1404h | 0700h | FFFEh | 0 | – | CL = 4: kaydırma sayısı |
| 6 | mov bh, ch | 0200h | 1435h | 1404h | 0700h | FFFEh | 0 | – | BH = saat = 14h |
| 7 | call bcdyaz | 0200h | 1435h | 1404h | 0700h | FFFCh | 0 | – | doğrudan bcdyaz |
| 8 | mov dl, bh | 0200h | 1435h | 1404h | 0714h | FFFCh | 0 | – | DL = 14h = 0001 0100b |
| 9 | shr dl, cl | 0200h | 1435h | 1404h | 0701h | FFFCh | 0 | – | 4 bit sağa: 01h |
| 10 | add dl, 30h | 0200h | 1435h | 1404h | 0731h | FFFCh | 0 | – | DL = 31h = '1' |
| 12 | int 21h | 0231h | 1435h | 1404h | 0731h | FFFCh | 0 | 1 | ekrana 1 |
| 13 | mov dl, bh | 0231h | 1435h | 1404h | 0714h | FFFCh | 0 | 1 | DL = 14h yeniden |
| 14 | and dl, 0Fh | 0231h | 1435h | 1404h | 0704h | FFFCh | 0 | 1 | üst 4 bit silinir: 04h |
| 15 | add dl, 30h | 0231h | 1435h | 1404h | 0734h | FFFCh | 0 | 1 | DL = 34h = '4' |
| 16 | int 21h | 0234h | 1435h | 1404h | 0734h | FFFCh | 0 | 14 | ekrana 4 |
| 17 | ret | 0234h | 1435h | 1404h | 0734h | FFFEh | 0 | 14 | dönüş |
| 18 | mov bh, bl | 0234h | 3535h | 1404h | 0734h | FFFEh | 0 | 14 | BH = dakika = 35h |
| 19 | call ikinokta | 0234h | 3535h | 1404h | 0734h | FFFCh | 0 | 14 | ikinokta girişi |
| 22 | int 21h | 023Ah | 3535h | 1404h | 073Ah | FFFCh | 0 | 14: | ekrana : |
| 23 | mov dl, bh | 023Ah | 3535h | 1404h | 0735h | FFFCh | 0 | 14: | bcdyaz'a kendiliğinden geçilir |
| 27 | int 21h | 0233h | 3535h | 1404h | 0733h | FFFCh | 0 | 14:3 | ekrana 3 |
| 31 | int 21h | 0235h | 3535h | 1404h | 0735h | FFFCh | 0 | 14:35 | ekrana 5 |
| 32 | ret | 0235h | 3535h | 1404h | 0735h | FFFEh | 0 | 14:35 | dönüş |
| 33 | mov bh, dh | 0235h | 0735h | 1404h | 0735h | FFFEh | 0 | 14:35 | BH = saniye = 07h |
| 37 | int 21h | 023Ah | 0735h | 1404h | 073Ah | FFFCh | 0 | 14:35: | ekrana : |
| 42 | int 21h | 0230h | 0735h | 1404h | 0730h | FFFCh | 0 | 14:35:0 | ekrana 0 |
| 46 | int 21h | 0237h | 0735h | 1404h | 0737h | FFFCh | 0 | 14:35:07 | ekrana 7 |
| 47 | ret | 0237h | 0735h | 1404h | 0737h | FFFEh | 0 | 14:35:07 | dönüş |
| 48 | ret | 0237h | 0735h | 1404h | 0737h | 0000h | 0 | 14:35:07 | program biter: SP = 0000h |
Saat için bcdyaz iki kez yazar. DL = 14h = 0001 0100b; SHR DL, CL dört bit sağa kaydırır ve DL = 01h olur. 30h eklenince '1' yazılır. Sonra DL'ye yeniden 14h konur, AND DL, 0Fh üst dört biti siler ve DL = 04h olur; ekrana '4' gider. AH, ilk çağrıdan sonra hâlâ 02h olduğundan ikinci INT 21h için yeniden yüklenmez. Dakikada ikinokta girişi önce ':' yazar; ardından komutlar bcdyaz etiketine kendiliğinden geçer. Etiket bir komut değildir, yalnız bir adrestir. Son durumda ekranda 14:35:07 vardır.
MOV CL, 4'ü dakikayı saklamadan yazmak. CL'deki 35h kaybolur ve dakika yerine 04h yazdırılır. Bir başka hata, 8086 için SHR DL, 4 yazmaktır. Bu biçim 80186 ve sonraki işlemcilerde vardır; 8086'da kaydırma sayısı ya 1 ya da CL'dir.
5.2.7.3BIOS veri alanı
BIOS, donanımın durumunu bellekte sabit bir yerde tutar: 0040h kesiminde, fiziksel olarak 00400h'den başlayan alanda. Bu alana BIOS veri alanı (BIOS data area) denir. INT 16h klavye tamponunu, INT 1Ah tık sayacını, INT 10h video modunu ve imleç konumlarını buradan okur. Program da aynı baytları doğrudan okuyabilir. Tablo 5.2.30 sık kullanılan konumları listeler.
| Adres | Boyut | İçerik |
|---|---|---|
| 0040:0010 | sözcük | donanım listesi (INT 11h'nin döndürdüğü değer) |
| 0040:0013 | sözcük | taban bellek, KB (INT 12h) |
| 0040:0017 | bayt | klavye bayrakları: bit 0 sağ Shift, 1 sol Shift, 2 Ctrl, 3 Alt, 4 Scroll Lock, 5 Num Lock, 6 Caps Lock, 7 Insert |
| 0040:001A | sözcük | tampon başı: sıradaki okunacak tuşun bağıl konumu |
| 0040:001C | sözcük | tampon sonu: sıradaki boş yerin bağıl konumu (baş = son → tampon boş) |
| 0040:001E–003D | 32 bayt | klavye tamponu: 16 sözcük (ASCII + tarama kodu), dairesel; en çok 15 tuş |
| 0040:0049 | bayt | geçerli video modu (03h, 13h …) |
| 0040:004A | sözcük | ekrandaki sütun sayısı (mod 03h'te 80) |
| 0040:0050 | 8 sözcük | 8 sayfanın imleç konumu (düşük bayt sütun, yüksek bayt satır) |
| 0040:006C | çift sözcük | tık sayacı: gece yarısından beri ≈ 18,2 Hz'lik kesme sayısı |
| 0040:0070 | bayt | gece yarısı geçti bayrağı (INT 1Ah/00h AL'de verir ve sıfırlar) |
Fiziksel adres, kesim değeri 16 ile çarpılıp bağıl konum eklenerek bulunur: 0040:006C = 00400h + 006Ch = 0046Ch. Aynı bayta 0000:046Ch adresiyle de ulaşılır; iki kesim:bağıl konum çifti aynı fiziksel adresi gösterir.
Klavye tamponu dairesel bir kuyruktur. INT 09h yeni tuşu “son” konumuna yazar ve sonu iki bayt ilerletir; INT 16h “baş” konumundan okur ve başı ilerletir. Konumlardan biri alanın sonuna (003Eh) gelince yeniden 001Eh'ye döner. Baş ile son eşitse tampon boştur. Bu yüzden 16 sözcüklük alana en çok 15 tuş sığar: 16. tuş yazılsaydı son, başa eşit olur ve dolu tampon boş sanılırdı.
0040:001Ah'de 0024h, 0040:001Ch'de 0028h okunuyor. Her tuş bir sözcük olduğundan bekleyen tuş sayısı (0028h − 0024h) ÷ 2 = 2'dir. Sıradaki tuşun ASCII kodu 0040:0024h'te, tarama kodu 0040:0025h'tedir. 0040:001Ah'nin fiziksel adresi 0041Ah'dir.
5.2.7.4Tık sayacıyla bekleme
Tık sayacı, kısa beklemeler için hazır bir saattir. Program başlangıç değerini okur, sonra sayaç istenen kadar artana kadar döngüde bekler. Aşağıdaki kod ayrıca klavye bayraklarından Caps Lock'u sınar ve tamponda bekleyen tuş olup olmadığına bakar.
; yaklaşık 1 saniye bekle
mov ax, 0040h
mov es, ax
mov bx, es:[006Ch] ; başlangıç tıkı
bekle:
mov ax, es:[006Ch] ; şimdiki tık
sub ax, bx ; geçen tık
cmp ax, 18 ; 18 tık ≈ 0,99 s
jb bekle
; Caps Lock açık mı? Bekleyen tuş var mı?
test byte ptr es:[0017h], 40h
jnz caps_acik ; bit 6 = 1
mov ax, es:[001Ah] ; tampon başı
cmp ax, es:[001Ch] ; tampon sonu
je tampon_bosBir tıkın süresi zamanlayıcının bölme oranından hesaplanır. Tablo 5.2.31 değerleri verir.
| Büyüklük | Hesap | Değer |
|---|---|---|
| Tık sıklığı | 1 193 182 Hz ÷ 65 536 | 18,2065 Hz |
| Bir tık | 65 536 ÷ 1 193 182 s | ≈ 54,9 ms |
| 18 tık | 18 × 54,925 ms | ≈ 0,989 s |
| 5 saniye | 5 × 18,2065 | ≈ 91 tık |
| Bir gün | sayacın sıfırlandığı değer | 1800B0h = 1 573 040 tık |
Bekleme süresi tık sayısıyla ölçüldüğü için çözünürlük yaklaşık 55 ms'dir; daha kısa süreler bu yolla ölçülemez. Kod sayacın yalnız düşük sözcüğünü okur. Fark alındığı için düşük sözcük FFFFh'den 0000h'ye dönse bile sonuç doğrudur: 16 bitlik çıkarma, 216'ya göre (mod 65 536) doğru farkı verir. Yalnız gece yarısındaki sıfırlama hesabı bozar, çünkü sayaç 1800B0h'den 0'a atlar.
Caps Lock denetimi TEST ile yapılır. 40h = 0100 0000b maskesi bit 6'yı seçer; bit 1 ise sonuç sıfır değildir, ZF = 0 olur ve JNZ atlar. TEST bayrağı yalnız okur, BIOS veri alanındaki baytı değiştirmez. Tampon denetimi baş ile sonu karşılaştırır; eşitse bekleyen tuş yoktur. emu8086 BIOS veri alanının tamamını gerçek PC'deki gibi güncellemez; tık sayacı ve klavye tamponu örnekleri DOSBox'ta tam çalışır.
Bitiş değerini başlangıca ekleyip sayaçla eşitlik aramak: cmp ax, hedef / jne bekle. Sayaç, döngünün tam o turda okumadığı bir anda hedefi geçebilir ve döngü bir sonraki taşmaya kadar sürer. Fark alıp JB ile “en az bu kadar geçti mi?” diye sormak güvenlidir.
5.2.8Program sonlandırma
5.2.8.1Üç yol ve çıkış kodu
Bir program işini bitirince denetimi DOS'a geri vermek zorundadır. İşlemci “programın sonu” diye bir şey bilmez; IP'nin gösterdiği baytı her zaman komut olarak yürütür. Sonlandırma komutu unutulursa işlemci programdan sonraki baytları, çoğu zaman programın verilerini, komut gibi çalıştırır. Sonuç kestirilemez: ekrana çöp basılabilir, sistem kilitlenebilir. DOS programı bitirmek için üç yol sunar (Tablo 5.2.32).
| Yöntem | Nasıl çalışır? | Nerede? |
|---|---|---|
ret | COM programında yığının üstünde 0000h vardır; RET, PSP:0000h'a döner, orada int 20h (CD 20) bulunur. | yalnız COM, yığın dengeliyse |
int 20h | DOS programı sonlandırır; CS'nin PSP kesimini göstermesi gerekir. | COM |
mov ax, 4C00hint 21h | AL'deki çıkış koduyla sonlandırır, açık dosyaları kapatır. | COM ve EXE · önerilen |
PSP (Program Segment Prefix, program kesimi öneki), DOS'un her programın önüne koyduğu 256 baytlık alandır. Komut satırı, ortam değişkenlerinin adresi ve dönüş bilgileri burada tutulur. İlk iki baytı CD 20'dir, yani INT 20h komutu. COM programları PSP'den hemen sonra yüklendiği için kod ORG 100h'den başlar.
RET'in COM programını neden bitirdiği yığından anlaşılır. DOS bir COM programını başlatırken SP'yi FFFEh yapar ve oraya 0000h sözcüğünü koyar. Program yığını dengeli bırakmışsa, yani her PUSH'u bir POP ve her CALL'u bir RET izlemişse, son RET bu 0000h'yi IP'ye yükler. CS hâlâ programın kesimidir ve CS:0000h PSP'nin başıdır. Orada INT 20h çalışır ve program biter. Yığında fazladan bir sözcük kalmışsa RET o sözcüğü adres sanar ve rastgele bir yere atlar.
Önerilen yol INT 21h/4Ch'dir. Hem COM hem EXE programında çalışır, CS'nin değerine bağlı değildir ve DOS'a bir çıkış kodu verir. Çıkış kodu AL'dedir: 0 başarı, sıfırdan farklı değerler hata anlamına gelir. Bir toplu iş dosyası (.BAT) bu kodu IF ERRORLEVEL 1 ile sınayıp farklı yollar izleyebilir.
5.2.8.2COM ve EXE şablonları
emu8086 yeni bir program için iki şablon sunar. COM şablonunda kod, veri ve yığın tek bir 64 KB'lık kesimdedir. EXE şablonunda her biri ayrı kesimde durur.
org 100h
mov dx, offset msg
mov ah, 09h
int 21h
ret ; ya da int 20h
msg db 'Merhaba$'COM programında CS = DS = ES = SS'dir; program kesim yazmaçlarını ayarlamaz. Program kod, veri ve yığın birlikte en fazla 64 KB olabilir. Dosya yalnız makine kodudur, başında bir başlık yoktur. DOS dosyayı PSP'nin hemen arkasına, 100h bağıl konumuna kopyalar ve yürütmeyi oradan başlatır.
.model small
.stack 100h
.data
msg db 'Merhaba$'
.code
basla:
mov ax, @data
mov ds, ax ; DS'yi ayarla!
mov dx, offset msg
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
end baslaEXE dosyasının başında bir başlık vardır. Başlık, programın hangi kesimlerden oluştuğunu ve yükleme adresine göre düzeltilmesi gereken yerleri (relocation, yeniden yerleştirme bilgisi) tutar. Giriş noktası end basla ile belirtilir ve program 64 KB'tan büyük olabilir. DOS başlangıçta CS:IP'yi giriş noktasına, SS:SP'yi yığın kesimine kurar. DS ve ES ise PSP'yi gösterir. Program veri kesimine erişmeden önce DS'yi kendisi ayarlamalıdır: mov ax, @data ve mov ds, ax. @data, veri kesiminin kesim değeridir; bu değeri yükleme sırasında DOS yerine koyar.
| Adım | Komut | AX | DS | DX | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|
| 1 | mov ax, @data | 0720h | 0700h | 0000h | – | @data = veri kesimi 0720h; DS hâlâ PSP'de |
| 2 | mov ds, ax | 0720h | 0720h | 0000h | – | DS = 0720h: veri kesimi |
| 3 | mov dx, offset msg | 0720h | 0720h | 0000h | – | msg veri kesiminin başında |
| 4 | mov ah, 09h | 0920h | 0720h | 0000h | – | AH = 09h |
| 5 | int 21h | 0924h | 0720h | 0000h | Merhaba | 0720:0000'dan '$'a kadar |
| 6 | mov ax, 4C00h | 4C00h | 0720h | 0000h | Merhaba | AH = 4Ch, AL = 00h |
| 7 | int 21h | 4C00h | 0720h | 0000h | Merhaba | çıkış kodu 0 ile DOS'a dönüş |
MOV DS, AX sonrası kesimler: PSP 0700h, yığın 0710h, veri 0720h (DS), kod 0721h (CS). Kesim değerleri emu8086'nın yerleşimidir; gerçek DOS'ta sayılar farklı olabilir, sıra ve DS ayarının gereği aynıdır.Başlangıçta DS = ES = 0700h'dir, yani PSP. Yığın kesimi 0710h'dir: PSP'nin 256 baytı 16 paragraf olduğu için 0700h + 10h. .stack 100h 256 baytlık yığın ayırır, o da 10h paragraf eder; veri kesimi bu yüzden 0720h'de başlar. 8 baytlık veri bir paragrafa sığar ve kod 0721h'de başlar. MOV AX, @data AX'e 0720h yükler; MOV DS, AX DS'yi veri kesimine çevirir. Kesim yazmacına anlık değer yazılamadığı için iki adım gerekir. msg veri kesiminin başındadır: OFFSET msg = 0000h. 09h, DS:DX = 0720:0000h'dan itibaren Merhaba yazar. Son iki satır çıkış kodu 0 ile DOS'a döner.
EXE programında RET kullanılamaz. DOS EXE'nin yığınına 0000h koymaz; SS:SP programın kendi yığın kesimini gösterir. RET orada ne bulursa ona atlar. MOV DS, AX satırı unutulursa DX doğru bağıl konumu tutar ama kesim yanlıştır: DS:DX PSP'nin başını gösterir ve ekrana PSP'nin baytları, yani çöp basılır.
5.2.9Uygulama: sonucu ikili yazdırmak
5.2.9.1Program
Bu kısımdaki program, birçok hizmeti küçük bir hesapla birleştirir. Önce 5 + 10 − 1 = 14 hesaplanır ve sonuç BL'ye yazılır. Sonra BL'nin sekiz biti, en anlamlı bitten (MSB) başlayarak tek tek '0' ya da '1' karakteri olarak ekrana basılır. En sonda ikili sayı eki 'b' yazılır ve bir tuşa basılması beklenir. Beklenen çıktı 00001110b'dir.
org 100h
mov al, 5 ; 00000101b
mov bl, 10 ; 0Ah = 00001010b
; 5 + 10 = 15 = 0Fh = 00001111b
add bl, al
; 15 - 1 = 14 = 0Eh = 00001110b
sub bl, 1
mov cx, 8 ; sonucu ikilik tabanda yazdır
print:
mov ah, 2 ; yazdırma fonksiyonu
mov dl, '0'
test bl, 10000000b ; ilk biti test et
jz zero
mov dl, '1'
zero:
int 21h
shl bl, 1
loop print
; ikili sayı eki b yazdır
mov dl, 'b'
int 21h
; klavye tuşu basılmasını bekle
mov ah, 0
int 16h
retSayının bellekte ya da yazmaçta “ikili hâle getirilmesi” gerekmez; sayı zaten ikilidir. Yazdırmak, her biti bir ASCII karakterine çevirmektir: 0 biti için 30h, 1 biti için 31h. Döngü her turda bit 7'ye bakar, karakteri yazar ve sayıyı bir sola kaydırır. Böylece bir sonraki bit bit 7'nin yerine gelir. Sekiz tur sonunda bütün bitler soldan sağa yazılmış olur.
5.2.9.2TEST ve SHL ile bit okuma
TEST BL, 10000000b, BL ile maskeyi bit bit VE'ler ama sonucu hiçbir yere yazmaz; yalnız bayrakları kurar. Maskenin tek 1 biti bit 7'dedir. BL'nin bit 7'si 0 ise VE sonucu 0 olur ve ZF = 1 kurulur. Bit 7 = 1 ise sonuç 80h olur ve ZF = 0'dır. JZ ZF = 1 iken atlar. TEST ayrıca CF ve OF'yi her zaman sıfırlar.
TEST BL, 10000000b: BL = 00001110b maskeyle VE'lenir, sonuç 00000000b'dir; ZF = 1 (bit 7 = 0). BL değişmez.SHL BL, 1 bütün bitleri bir sola kaydırır. Bit 7'den çıkan bit CF'ye gider, bit 0'a 0 girer. Bir sonraki bit artık bit 7'nin yerindedir. TEST sonucu saklamadığı için BL'yi bozmaz; onu bilerek değiştiren yalnız SHL'dir.
SHL BL, 1: 00001110b → 00011100b; çıkan bit 7 (0) CF'ye gider, sağdan 0 girer.Aynı iş SHL ile CF'ye bakarak da yapılabilir: önce SHL BL, 1, sonra JC ile çıkan bitin 1 olup olmadığı sınanır. Bu sıralamada kaydırma yazdırmadan önce yapılmalıdır; çünkü bitin değeri artık BL'de değil CF'dedir. MOV AH, 2'nin her turda yeniden yapılmasının bir nedeni de vardır: INT 21h/02h AH'yi bozmaz ama döngüye sonradan bir başka hizmet eklenirse AH korunmuş olur.
5.2.9.3Kod izleme
Hesaplama kısmında bayrakların nasıl değiştiği Tablo 5.2.34'de görülür. MOV komutları bayraklara dokunmaz. ADD BL, AL 0Ah + 05h = 0Fh üretir ve taşma yoktur (CF = 0). Sonuçta dört 1 biti vardır; parite çift olduğu için PF = 1'dir. SUB BL, 1 0Eh = 00001110b üretir; üç 1 biti PF'yi 0 yapar, ödünç yoktur (CF = 0).
| Adım | Komut | AH | DL | BL | CX | ZF | CF | PF | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | mov al, 5 | 00h | 00h | 00h | 0000h | 0 | 0 | 0 | – | AL = 05h; MOV bayrak değiştirmez |
| 2 | mov bl, 10 | 00h | 00h | 0Ah | 0000h | 0 | 0 | 0 | – | BL = 0Ah |
| 3 | add bl, al | 00h | 00h | 0Fh | 0000h | 0 | 0 | 1 | – | 0Ah + 05h = 0Fh; dört 1 biti: PF = 1 |
| 4 | sub bl, 1 | 00h | 00h | 0Eh | 0000h | 0 | 0 | 0 | – | 0Fh − 1 = 0Eh; üç 1 biti: PF = 0 |
| 5 | mov cx, 8 | 00h | 00h | 0Eh | 0008h | 0 | 0 | 0 | – | sekiz bit için sekiz tur |
Döngünün sekiz turu aynı kalıbı izler. Tablo 5.2.35 iki turu adım adım verir: bit 7'nin 0 olduğu ilk tur ve 1 olduğu beşinci tur. İlk turda TEST ZF = 1 yapar, JZ atlar ve DL'deki '0' yazılır. Beşinci turda BL = E0h'dir; TEST ZF = 0 yapar, JZ atlamaz, MOV DL, '1' çalışır ve '1' yazılır. Her iki turda da SHL çıkan biti CF'ye, LOOP ise CX'i bir azaltır.
| Adım | Komut | AH | DL | BL | CX | ZF | CF | PF | Ekran (çıktı) | Açıklama |
|---|---|---|---|---|---|---|---|---|---|---|
| 6 | mov ah, 2 | 02h | 00h | 0Eh | 0008h | 0 | 0 | 0 | – | tur 1: AH = 2 |
| 7 | mov dl, '0' | 02h | 30h | 0Eh | 0008h | 0 | 0 | 0 | – | varsayılan '0' |
| 8 | test bl, 10000000b | 02h | 30h | 0Eh | 0008h | 1 | 0 | 1 | – | 0Eh AND 80h = 0: ZF = 1 |
| 9 | jz zero | 02h | 30h | 0Eh | 0008h | 1 | 0 | 1 | – | ZF = 1: zero'ya atla |
| 10 | int 21h | 02h | 30h | 0Eh | 0008h | 1 | 0 | 1 | 0 | ekrana 0 |
| 11 | shl bl, 1 | 02h | 30h | 1Ch | 0008h | 0 | 0 | 0 | 0 | BL = 1Ch; çıkan bit 0 |
| 12 | loop print | 02h | 30h | 1Ch | 0007h | 0 | 0 | 0 | 0 | CX = 7 ≠ 0: print'e |
| 34 | mov ah, 2 | 02h | 30h | E0h | 0004h | 0 | 0 | 0 | 0000 | tur 5: AH = 2 |
| 35 | mov dl, '0' | 02h | 30h | E0h | 0004h | 0 | 0 | 0 | 0000 | varsayılan '0' |
| 36 | test bl, 10000000b | 02h | 30h | E0h | 0004h | 0 | 0 | 0 | 0000 | E0h AND 80h = 80h: ZF = 0 |
| 37 | jz zero | 02h | 30h | E0h | 0004h | 0 | 0 | 0 | 0000 | atlama yok |
| 38 | mov dl, '1' | 02h | 31h | E0h | 0004h | 0 | 0 | 0 | 0000 | DL = '1' |
| 39 | int 21h | 02h | 31h | E0h | 0004h | 0 | 0 | 0 | 00001 | ekrana 1 |
| 40 | shl bl, 1 | 02h | 31h | C0h | 0004h | 0 | 1 | 1 | 00001 | BL = C0h; çıkan bit CF = 1 |
| 41 | loop print | 02h | 31h | C0h | 0003h | 0 | 1 | 1 | 00001 | CX = 3 ≠ 0: print'e |
Tablo 5.2.36 sekiz turun özetidir. BL her turda bir sola kayar: 0Eh, 1Ch, 38h, 70h, E0h, C0h, 80h, 00h. Bit 7 sütunu, yazılan karakterlerin sırasını verir: 0, 0, 0, 0, 1, 1, 1, 0. Bu, 0Eh'nin ikili yazılışıdır. Sekizinci turdan sonra CX = 0 olur ve LOOP atlamaz.
| Tur | BL (TEST öncesi) | Bit 7 | Yazılan | BL (SHL sonrası) | CF | CX | Ekran |
|---|---|---|---|---|---|---|---|
| 1 | 0Eh = 00001110 | 0 | 0 | 1Ch | 0 | 0007h | 0 |
| 2 | 1Ch = 00011100 | 0 | 0 | 38h | 0 | 0006h | 00 |
| 3 | 38h = 00111000 | 0 | 0 | 70h | 0 | 0005h | 000 |
| 4 | 70h = 01110000 | 0 | 0 | E0h | 0 | 0004h | 0000 |
| 5 | E0h = 11100000 | 1 | 1 | C0h | 1 | 0003h | 00001 |
| 6 | C0h = 11000000 | 1 | 1 | 80h | 1 | 0002h | 000011 |
| 7 | 80h = 10000000 | 1 | 1 | 00h | 1 | 0001h | 0000111 |
| 8 | 00h = 00000000 | 0 | 0 | 00h | 0 | 0000h | 00001110 |
Döngüden sonra DL = 'b' yapılır ve AH hâlâ 2 olduğu için INT 21h doğrudan 'b'yi yazar. MOV AH, 0 ve INT 16h bir tuş bekler; izlemede Enter'a basıldığında AH = 1Ch (tarama kodu), AL = 0Dh döner. Son RET programı bitirir. Ekranın son hâli şöyledir:
00001110b_Aynı döngü BL = B5h ile çalışsın. B5h = 1011 0101b'dir. Turlarda bit 7 sırasıyla 1, 0, 1, 1, 0, 1, 0, 1 olur ve ekrana 10110101b yazılır. Turlarda SHL'nin CF'ye attığı bitler de aynı sırayı izler, çünkü çıkan bit her turda TEST'in baktığı bittir.
Programdan çıkan dersler kısadır. LOOP CX'i azalttığı için döngü içinde CX başka bir işe kullanılmaz. INT 21h/02h AL'yi değiştirir (AL = DL); AL'de saklanan bir değer varsa önce korunur. TEST bayrakları kurar ama işleneni değiştirmez; bu yüzden aynı yazmaç birçok maskeyle art arda sınanabilir.
5.2.9.4Mini menü
Son program, bir kullanıcı arayüzünün iskeletidir: bir menü gösterir, bir tuş okur ve tuşa göre iş yapar. '1' tuşu selam verir, 'q' programı bitirir, başka bir tuş menüyü yeniden gösterir.
org 100h
goster:
mov dx, offset menu
mov ah, 09h
int 21h
mov ah, 01h ; seçimi oku
int 21h
cmp al, 'q'
je cikis
cmp al, '1'
jne goster
mov dx, offset selam
mov ah, 09h
int 21h
jmp goster
cikis:
mov ax, 4C00h ; çıkış kodu 0
int 21h
menu db 0Dh, 0Ah, '1:Selam q:Cikis $'
selam db 0Dh, 0Ah, 'Selam!$'Kullanıcı önce 1, sonra q basıyor. Tablo 5.2.37 izlemeyi verir.
Menü metni CR LF ile başladığı için her gösterimde yeni bir satıra yazılır. AH = 01h tuşu okur ve yansıtır; kullanıcının bastığı 1 menünün hemen yanında görünür. İlk karşılaştırma 31h ile 71h ('q') arasındadır; eşit değildir, ZF = 0 olur ve JE atlamaz. İkinci karşılaştırma '1' ile yapılır; eşittir, ZF = 1 olur ve JNE atlamaz. selam yazılır ve JMP menüye döner. İkinci turda q okunur, CMP AL, 'q' ZF = 1 yapar ve JE cikis'a atlar. MOV AX, 4C00h AH = 4Ch ve AL = 00h'yi tek komutta kurar; program çıkış kodu 0 ile biter. Ekranın son durumu şudur:
1:Selam q:Cikis 1
Selam!
1:Selam q:Cikis qVeri, son komuttan sonra durur. INT 21h/4Ch geri dönmediği için işlemci menu'nün baytlarına hiç ulaşmaz. Sonlandırma satırları silinseydi işlemci 0Dh, 0Ah, '1' … baytlarını komut olarak çözmeye çalışırdı.
5.2.9.5Sık yapılan hatalar
Hizmet çağıran programlardaki hataların çoğu birkaç kalıba girer. Tablo 5.2.38 bunları nedenleri ve düzeltmeleriyle toplar.
| Hata | Sonuç | Düzeltme |
|---|---|---|
| '$' unutuldu | INT 21h/09h belleği '$' bulana kadar yazar; ekrana çöp dolar | dizginin sonuna '$' |
| DS ayarlanmadı (EXE) | DX doğru ama kesim yanlış; PSP yazılır | mov ax, @data · mov ds, ax |
| AL'nin bozulması | 02h ve 09h AL'yi değiştirir; okunan karakter kaybolur | değeri başka yazmaçta saklamak |
| 09h sonrası imleç | INT 10h/09h imleci ilerletmez; sonraki yazı üstüne gelir | imleci 02h ile taşımak |
| 13h'te DS:DX | BIOS dizgi hizmeti adresi ES:BP'de bekler | lea bp, dizgi; DX konum |
| 0Ah tamponu | kapasite yazılmamış ya da metin tampon+0'dan okunmuş | bayt 0 = kapasite; metin tampon+2'de |
| Yalnız LF | imleç alt satıra iner, satır başına gelmez | CR + LF (0Dh, 0Ah) |
| Sonlandırma yok | veriler komut olarak yürütülür | RET (COM) ya da INT 21h/4Ch |
Okunan tuşu yeni satırda yeniden yazmak için şu sıra kullanılıyor: AH = 01h ile oku, AH = 02h ile CR ve LF yaz, sonra MOV DL, AL ile tuşu yaz. Kullanıcı k bastığında ekranda yalnız yansıtılan k görünür ve imleç iki satır aşağı iner. Son 02h çağrısından sonra AL = 0Ah'dir; MOV DL, AL tuşu değil LF'yi alır. Okunan tuş hemen MOV BL, AL ile saklanır, sonra MOV DL, BL yazılır.
5.2.10Alıştırmalar ve çözümleri
Sunumdaki alıştırmalar aşağıda çözümleriyle verilir. Program yazılan alıştırmalarda kod, ardından çözümün kısa açıklaması gelir. Çözümler tek yol değildir; aynı işi başka hizmetlerle yapan programlar da doğrudur.
Alıştırma 1. Ekranın tam ortasına (12, 38) mavi zemin üzerine beyaz “8086” yazan program INT 10h/13h ile nasıl yazılır?
org 100h
mov ax, 1301h ; AH=13h, AL=01h
mov bx, 001Fh ; BH=0, BL=1Fh
mov cx, 4 ; 4 karakter
mov dx, 0C26h ; satır 12, sütun 38
lea bp, yazi ; ES:BP → dizgi
int 10h
ret
yazi db '8086'Dört karakter 38–41. sütunlara yazılır; 80 sütunluk ekranın ortası 40 olduğundan yazı ortalanmıştır. DX = 0C26h, DH = 0Ch = 12 ve DL = 26h = 38 demektir. BL = 1Fh mavi zemin, beyaz yazıdır. COM programında ES = DS olduğu için ES ayrıca kurulmaz. İlk hücrenin görüntü belleğindeki yeri (12 × 80 + 38) × 2 = 07CCh'dir.
Alıştırma 2. Kullanıcıdan iki rakam okuyup (01h) toplamlarını tek basamak olarak yazdıran program (toplam ≤ 9) nasıl yazılır?
org 100h
mov ah, 01h
int 21h ; birinci rakam
sub al, 30h
mov bl, al
mov ah, 01h
int 21h ; ikinci rakam
sub al, 30h
add bl, al ; BL = toplam
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
mov dl, bl
add dl, 30h ; ASCII rakam
int 21h
retHer rakamdan 30h çıkarılarak sayı değeri bulunur. Birinci sayı BL'de saklanır, çünkü ikinci okuma AL'yi değiştirir. Toplam BL'de oluşur ve CR LF'den sonra 30h eklenerek yazılır. Kullanıcı 3 ve 5 bastığında ekranda 35, alt satırda 8 görünür.
Alıştırma 3. Esc'ye basılana kadar basılan tuşların tarama kodunu onaltılık yazdıran program nasıl yazılır?
org 100h
oku:
mov ah, 0
int 16h ; AH = tarama, AL = ASCII
cmp al, 1Bh ; Esc?
je son
lea bx, hex ; XLAT tablosu
mov dh, ah ; tarama kodunu sakla
mov al, dh
mov cl, 4
shr al, cl ; üst basamak
xlat
mov dl, al
mov ah, 02h
int 21h
mov al, dh
and al, 0Fh ; alt basamak
xlat
mov dl, al
int 21h
mov dl, ' '
int 21h
jmp oku
son: ret
hex db '0123456789ABCDEF'Tarama kodu AH'de gelir ve DH'de saklanır; çünkü AL ve AH, XLAT ve 02h çağrılarıyla değişecektir. XLAT, AL ← [BX + AL] işlemini yapar: 0–15 arasındaki bir sayıyı tablodaki karaktere çevirir. Üst basamak dört bit sağa kaydırılarak, alt basamak 0Fh ile maskelenerek ayrılır. a ve 1 tuşlarına basılınca ekranda 1E 02 görünür; Esc programı bitirir.
Alıştırma 4. 0Ah ile okunan metni tersten yazdıran program nasıl yazılır?
org 100h
mov dx, offset tampon
mov ah, 0Ah
int 21h ; satır oku
mov ah, 02h
mov dl, 0Ah ; alt satır (Enter CR basmıştı)
int 21h
mov cl, [tampon+1] ; okunan sayı
mov ch, 0
jcxz bitti
mov si, offset tampon+1
add si, cx ; son karakter
std ; geriye doğru
ters:
lodsb
mov dl, al
int 21h
loop ters
cld
bitti: ret
tampon db 20, ?, 20 dup(?)Metin tampon+2'den başlar ve uzunluğu [tampon+1]'dedir. Son karakter tampon + 2 + sayı − 1 = tampon + 1 + sayı adresindedir; SI oraya kurulur. STD yön bayrağını kurar ve LODSB her turda AL ← [SI] yapıp SI'yi bir azaltır. CX = sayı olduğundan LOOP her karakteri bir kez yazar. Boş satırda (sayı 0) JCXZ döngüye hiç girmez; yoksa LOOP CX'i 0'dan FFFFh'ye indirip 65 536 tur dönerdi. Program sonunda CLD yön bayrağını varsayılana döndürür. Mikro yazılınca alt satırda orkiM görünür.
Alıştırma 5. Tarih GG.AA.YYYY biçiminde nasıl yazdırılır? Yıl için hangi yöntem kullanılır?
org 100h
mov ah, 2Ah
int 21h ; CX=yıl DH=ay DL=gün
mov bx, cx ; yılı sakla
mov al, dl
call iki ; GG
mov dl, '.'
int 21h
mov al, dh
call iki ; AA
mov dl, '.'
int 21h
mov ax, bx ; yıl
mov cx, 0 ; basamak sayacı
mov si, 10
bol:
xor dx, dx
div si ; DX:AX / 10
push dx ; kalan = basamak
inc cx
test ax, ax
jnz bol
mov ah, 02h
yaz:
pop dx
add dl, 30h
int 21h
loop yaz
ret
iki: ; AL (0-99) → 2 hane, DH korunur
push dx
aam
add ax, 3030h
push ax
mov dl, ah
mov ah, 02h
int 21h
pop ax
mov dl, al
mov ah, 02h
int 21h
pop dx
retGün ve ay 99'dan küçük olduğu için AAM yeterlidir; iki yordamı DH'deki ayı yığında korur. Yıl 16 bitlik bir sayıdır ve AAM ile ayrılamaz. Yıl 10'a tekrar tekrar bölünür: DIV SI DX:AX'i 10'a böler, bölümü AX'e, kalanı DX'e yazar. Kalanlar birler, onlar, yüzler, binler sırasıyla çıkar; yazılış sırası ise tersidir. Bu yüzden kalanlar yığına itilir ve sonra çekilerek yazılır. Her bölmeden önce DX sıfırlanır, çünkü DIV bölüneni DX:AX olarak alır. 7 Ocak 2026 için ekrana 07.01.2026 yazılır.
Alıştırma 6. mov ah, 09h / int 21h ile '$' karakteri nasıl yazdırılır?
Yazdırılamaz; 09h ilk '$'ı dizginin sonu sayar ve yazmaz. '$' için 02h hizmeti kullanılır: mov ah, 02h, mov dl, '$' (24h), int 21h. INT 10h/0Eh ile AL = 24h da aynı işi görür.
Alıştırma 7. Mod 13h'te (160, 100) pikselinin A000h kesimindeki bağıl konumu nedir?
100 × 320 + 160 = 32 160 = 7DA0h. Fiziksel adres A7DA0h'dir.
Alıştırma 8. INT 1Ah/02h DH = 59h döndürdü. Ekrana ne yazılır? Aynı saniye INT 21h/2Ch ile hangi değerle gelir?
59h paketli BCD'dir: üst nibble 5, alt nibble 9; ekrana 59 yazılır. INT 21h/2Ch saniyeyi ikili verir: 59 = 3Bh, yani DH = 3Bh.
Alıştırma 9. 0040:006C tık sayacıyla yaklaşık 5 saniye beklemek için kaç tık beklenmelidir?
5 × 18,2065 ≈ 91 tık. Tık başına 54,9 ms ile 91 tık 4,998 saniyedir.
5.2.11Özet
- BIOS donanımı doğrudan süren ROM yordamlarıdır; DOS onun üstünde dosya, dizgi, saat ve program hizmetleri sunar. Program ikisine de
INT nile, hizmetin adresini bilmeden ulaşır. - Hizmet çağırma kalıbı: AH ← hizmet numarası, öteki yazmaçlara parametreler,
INT n, sonuç yazmaçlarda ya da bayraklarda. Hizmetler bazı yazmaçları değiştirir: INT 21h/02h AL = DL, 09h AL = 24h yapar. - Yeni satır CR LF (0Dh, 0Ah) ister. Rakam = kod − 30h; büyük ve küçük harf bit 5 ile ayrılır.
- INT 10h: 00h mod seçer ve ekranı siler; 02h/03h imleci yazar ve okur. 09h renkli yazar ama imleci ilerletmez; 0Eh teletype yazar ve imleci ilerletir. 13h ES:BP'deki CX uzunluklu dizgiyi yazar; 06h bir pencereyi kaydırır ya da siler.
- Öznitelik = arka plan × 16 + ön plan; bit 7 yanıp sönme. 07h varsayılan, 1Fh mavi zemin beyaz yazı, 4Eh kırmızı zemin sarı yazıdır.
- Mod 03h'te görüntü belleği B800:0000h'dadır; hücre (satır × 80 + sütun) × 2 adresindedir, çift baytta karakter, tek baytta öznitelik. Mod 13h'te A000:0000h'dan itibaren piksel başına bir bayt, adres y × 320 + x'tir.
- INT 16h/00h tuş bekler ve AH'ye tarama kodunu, AL'ye ASCII'yi verir; genişletilmiş tuşlarda AL = 00h'dir. 01h beklemeden yoklar: ZF = 1 tuş yok.
- INT 21h: 01h oku ve yansıt, 02h DL'yi yaz, 09h '$' ile biten dizgiyi yaz, 0Ah tamponlu satır oku. DOS çıktısı yönlendirilebilir, BIOS çıktısı yönlendirilemez.
- 0Ah tamponu: bayt 0 kapasite, bayt 1 okunan sayı, metin bayt 2'den başlar ve 0Dh ile biter.
- INT 21h/2Ah ve 2Ch tarih ve saati ikili verir (AAM ile yazdırılır); INT 1Ah/02h RTC saatini paketli BCD verir (SHR ve AND ile yazdırılır).
- BIOS veri alanı 0040h kesimindedir: klavye bayrakları 0017h, tampon başı ve sonu 001Ah ve 001Ch, tık sayacı 006Ch. Tık sıklığı 18,2065 Hz, bir tık ≈ 54,9 ms'dir.
- Program RET (yalnız dengeli yığınlı COM), INT 20h (COM) ya da önerilen INT 21h/4Ch ile biter; AL çıkış kodudur. EXE programı DS'yi
@dataile kendisi ayarlar.
5.2.12Kavram listesi
- BIOS Basic Input/Output System
- yazılım kesmesi software interrupt
- kesme vektörü interrupt vector
- ASCII ASCII
- video modu video mode
- imleç cursor
- öznitelik baytı attribute byte
- piksel pixel
- little-endian little-endian
- tarama kodu scan code
- klavye tamponu keyboard buffer
- yoklama polling
- paketli / paketsiz BCD packed / unpacked BCD
- nibble nibble
- gerçek zamanlı saat (RTC) real-time clock
- PSP (program kesimi öneki) program segment prefix
- program sonlandırma program termination
- öykünücü emulator
5.2.13Kendini Dene
Mod 03h'te imleç (24, 0)'dayken INT 10h, AH = 09h ile AL = '-', BL = 1Eh, CX = 80 yazılıyor. Ekranda ne görünür, imleç nerede kalır?
Cevap
Son satırın 80 hücresinin hepsine mavi zemin üzerine sarı '-' yazılır. 09h imleci ilerletmez ve ekranı kaydırmaz; imleç (24, 0)'da kalır. Aynı satır 80 kez 0Eh ile yazılsaydı son karakterden sonra imleç alt satıra geçmeye çalışır ve ekran bir satır yukarı kayardı.
Kırmızı zemin üzerinde yanıp sönen beyaz yazının öznitelik baytı nedir?
Cevap
Bit 7 = 1 (yanıp sönme), arka plan 100b (kırmızı), ön plan 1111b (beyaz): 1100 1111b = CFh.
Mod 03h'te son satırın ilk hücresinin (24, 0) karakter baytı hangi bağıl konumdadır? Fiziksel adresi nedir?
Cevap
(24 × 80 + 0) × 2 = 3840 = 0F00h. Karakter B800:0F00h'da, öznitelik B800:0F01h'dedir. Fiziksel adres B8000h + 0F00h = B8F00h.
tampon db 4, ?, 4 dup(?)tanımlı tampona INT 21h/0Ah ile okunurken kullanıcı abcdef yazıp Enter'a basıyor. Tamponun ilk altı baytı ne olur?Cevap
Kapasite Enter dahil 4 olduğundan en çok 3 karakter alınır; d, e ve f'de zil çalar. Tampon
04 03 61 62 63 0Dolur: kapasite, okunan sayı 3, 'a', 'b', 'c' ve Enter.mov ah, 02h,mov dl, 'Z',int 21hkomutlarından sonra AL kaçtır?Cevap
INT 21h/02h dönüşte AL'ye DL'yi koyar: AL = 5Ah ('Z'). AL'de daha önce saklanan bir değer varsa kaybolmuştur.
Saat 23:00. Saati DOS'tan (INT 21h/2Ch) okuyan program CH'yi BCD yazan yordama (SHR/AND) gönderiyor. Ekranda ne görünür? RTC'den okunan CH, AAM kullanan yordama gönderilseydi ne görünürdü?
Cevap
DOS ikili verir: CH = 23 = 17h. BCD yordamı nibble'ları 1 ve 7 olarak ayırır ve 17 yazar. RTC ise CH = 23h verir; AAM bunu ikili 35 sayar (23h = 35) ve 35 yazılır. Her iki durumda da doğru değer 23'tür.
Tık sayacıyla yaklaşık 3 saniye beklemek için kaç tık beklenmelidir? Bu yolla 10 ms'lik bir bekleme ölçülebilir mi?
Cevap
3 × 18,2065 ≈ 54,6; yaklaşık 55 tık. 10 ms ölçülemez: bir tık yaklaşık 54,9 ms'dir ve sayaç bu süreden kısa aralıkları ayırt edemez.
Mod 13h'te (200, 150) pikselinin bağıl konumu nedir? Bir sağdaki ve bir alttaki piksellerin konumları nedir?
Cevap
150 × 320 + 200 = 48 200 = BC48h. Bir sağdaki (201, 150) BC49h, bir alttaki (200, 151) BC48h + 140h = BD88h'dedir.
BIOS veri alanında tampon başı 003Ch, tampon sonu 0020h okunuyor. Kaç tuş bekliyor?
Cevap
Tampon dairesel olduğu için son, başın gerisinde kalmış olabilir. Baştan alanın sonuna kadar (003Ch–003Dh) bir sözcük, alanın başından sona kadar (001Eh–001Fh) bir sözcük vardır: 2 tuş. Genel formül (son − baş + 32) mod 32, bölü 2'dir: (20h − 3Ch + 20h) = 4 bayt.
Bir EXE programı
MOV AX, 4C00h·INT 21hyerineRETile bitiyor. Ne olur?Cevap
EXE'nin yığınında DOS'un koyduğu 0000h sözcüğü yoktur ve CS PSP'yi göstermez. RET, yığının üstünde ne bulursa onu IP'ye yükler ve kod kesiminde rastgele bir adrese atlar. Program kilitlenebilir. EXE programı INT 21h/4Ch ile bitirilir.
5.2.14İleri okuma
- Ralf Brown, Ralf Brown's Interrupt List: INT 10h, 16h, 1Ah ve 21h'nin bütün hizmetlerini, yazmaç düzeyinde ve BIOS sürüm farklarıyla anlatan başvuru listesi.
- IBM, Personal Computer AT Technical Reference, 1984: BIOS kaynak listesi; BIOS veri alanının, klavye ve zamanlayıcı kesmelerinin özgün tanımı.
- Peter Abel, IBM PC Assembly Language and Programming, 5. baskı: ekran, klavye ve DOS hizmetlerini çok sayıda örnek programla işler.
- Barry B. Brey, The Intel Microprocessors, 8. baskı: BIOS ve DOS çağrılarını 8086 donanımı ve kesme yapısıyla birlikte ele alır.
5.2.15Kaynaklar
- R. Brown, Ralf Brown's Interrupt List (INT 10h, 16h, 21h ayrıntılı başvuru).
- IBM, Personal Computer AT Technical Reference, BIOS bölümü, 1984.
- P. Abel, IBM PC Assembly Language and Programming, 5. baskı, Prentice Hall, 2001.
- B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009.
- emu8086 yardım belgeleri: supported interrupt functions.
- Ş. Ç. Öztürk, O. Ergin, Intel 8086 ile Mikroişlemci Programlamaya Giriş, 2009.
- Intel, 8086 16-Bit HMOS Microprocessor veri sayfası (komut süreleri).
İlgili sayfalar: Bölüm 5.2 sunumu · Çalışma soruları · Terim sözlüğü · © Sercan Külcü. Tüm hakları saklıdır.