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.

Uygulama programımov ah, 09h / int 21hDOS hizmetleri: INT 20h, INT 21hdosya, dizgi, saat/tarih, program sonuBIOS hizmetleri: INT 10h, 13h, 16h, 1AhROM'daki aygıt yordamlarıDonanımekran kartı, klavye denetleyicisi, disk, saatdoğrudan porterişimi (IN/OUT)
Şekil 5.2.1: Hizmet katmanları. Uygulama DOS'u 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.
Tanım 5.2.1

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.

Tanım 5.2.2

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ğır

Birinci 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.

Tablo 5.2.1: Sık kullanılan BIOS ve DOS kesmeleri.
KesmeSağlayanGörev
INT 10hBIOSvideo: mod, imleç, karakter, dizgi, piksel
INT 13hBIOSdisk
INT 16hBIOSklavye
INT 1AhBIOSsaat sayacı, gerçek zamanlı saat
INT 20hDOSprogramı sonlandır (COM)
INT 21hDOSyü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.

Sık yapılan hata

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.

Tablo 5.2.2: Sık karşılaşılan denetim karakterleri ve INT 10h/0Eh ile INT 21h/02h'deki etkileri.
KodAdEtki
07hBELzil sesi
08hBSimleç bir geri (karakter silinmez)
09hTABsekme (DOS hizmetlerinde)
0AhLFimleç bir alt satıra
0DhCRimleç satır başına; Enter tuşunun kodu
1BhESCEsc 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).

Tablo 5.2.3: ASCII tablosundaki düzenler.
KarakterASCIIİlişki
boşluk20hbasılabilir karakterlerin ilki
'0' … '9'30h–39hrakam = kod − 30h
'A' … 'Z'41h–5Ahbit 5 = 0
'a' … 'z'61h–7Ahbit 5 = 1 (+20h)
'$'24hINT 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.

yalnız CR (0Dh)ABCyalnız LF (0Ah)ABCCR + LFABC
Şekil 5.2.2: CR ve LF'nin etkisi. Yalnız CR satırın başına döndürür; yalnız LF bir alt satıra indirir ama sütunu korur; CR LF birlikte yeni satır açar.

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.

Örnek 5.2.1

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.

Tablo 5.2.4: INT 10h video hizmetleri.
AHHizmetGirişÇıkış / açıklama
00hvideo modu seçAL = mod (03h: 80×25 renkli metin)ekran temizlenir
01himleç şekliCH = başlangıç, CL = bitiş satırıCH = 20h → imleç gizli
02himleci konumlaBH = sayfa, DH = satır, DL = sütun–
03himleç konumunu okuBH = sayfaDH, DL = konum; CH, CL = şekil
06hpencereyi yukarı kaydırAL = satır sayısı (0 = temizle), BH = öznitelik, CH,CL – DH,DL = köşelerekranı ya da bir pencereyi siler
09hkarakter ve öznitelik yazAL = karakter, BH = sayfa, BL = öznitelik, CX = tekrarimleç ilerlemez
0Ahyalnız karakter yazAL, BH, CXhücrenin özniteliği korunur
0Chpiksel yazAL = renk, BH = sayfa, CX = x, DX = ygrafik modlarda
0Ehteletype çıkışıAL = karakter, BH = sayfaimleç ilerler; CR, LF, BS, BEL yorumlanır
13hdizgi yazAL = mod, BH, BL, CX = uzunluk, DH,DL = konum, ES:BP = dizgiAT 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.

Tablo 5.2.5: Sık kullanılan video modları.
ALModGörüntü belleği
01h40×25 metin, 16 renkB800h
03h80×25 metin, 16 renkB800h
07h80×25 tek renkB000h
04h320×200 grafik, 4 renkB800h
13h320×200 grafik, 256 renkA000h

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 ekran

AH 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.

010203040506070790510152024(DH = 1, DL = 4)DL: sütun 0–79 →DHsatır0–24
Şekil 5.2.3: 80×25 metin ekranı. Satır DH'de (0–24), sütun DL'de (0–79) verilir; işaretli hücre (DH = 1, DL = 4) konumudur.

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.

(12, 40) → (12, 41)DH = 0Ch = 12 (satır), DL = 28h = 40 (sütun)03h ile oku → inc dl → 02h ile yaz: (12, 41)bağıl konum (12 × 80 + 40) × 2 = 07D0h
Şekil 5.2.4: 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.

B7R6G5B4I3R2G1B0yanıp sönmearka plan RGBparlakön plan RGBÖrnek: 1Eh = 0001 1110b → mavi zemin, sarı (parlak kahverengi) yazı
Şekil 5.2.5: Öznitelik baytı: bit 7 yanıp sönme, bit 6–4 arka plan (RGB), bit 3 parlaklık, bit 2–0 ön plan (RGB). 1Eh = 0001 1110b mavi zemin üzerine sarı yazıdır.
Tanım 5.2.3

Ö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.

Tablo 5.2.6: Metin modunun on altı rengi.
NoRenkNoRenk
0siyah8koyu gri
1mavi9açık mavi
2yeşilAaçık yeşil
3camgöbeğiBaçık camgöbeği
4kırmızıCaçık kırmızı
5eflatunDaçık eflatun
6kahverengiEsarı
7açık griFbeyaz
Örnek 5.2.2

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.

Tablo 5.2.7: AH = 09h ile AH = 0Eh karşılaştırması.
ÖzellikAH = 09hAH = 0Eh (teletype)
GirişlerAL = karakter, BH = sayfa, BL = öznitelik, CX = tekrarAL = karakter, BH = sayfa
Renkvar (BL)metin modunda yok; hücrenin rengi korunur
İmleçilerlemezilerler; satır sonunda alt satıra geçer
CR, LF, BS, BELsembol olarak basılır (♪, ◘ …)komut olarak yorumlanır
Ekran kaydırmayokson satırda ekran yukarı kayar
Tipik kullanımrenkli kutular, çerçeveler, aynı karakteri CX kezdüz metin akışı
AH = 09h, AL = '*', CX = 3***imleç başta kaldıAH = 0Eh, AL = 'A'Aimleç bir sağda
Şekil 5.2.6: 09h üç yıldızı yazar ama imleç ilk hücrede kalır; 0Eh 'A'yı yazar ve imleci bir sağa taşır.

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.

Sık yapılan hata

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
ret

Program 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ı.

Tablo 5.2.8: Mod, imleç, 09h ve 0Eh programının izlemesi (her satır, komut yürütüldükten sonraki durum).
AdımKomutAXBXCXDXİmleçAçıklama
1mov ax, 0003h0003h0000h0000h0000h(0, 0)AH = 00h (mod seç), AL = 03h (80×25 metin)
2int 10h0003h0000h0000h0000h(0, 0)mod kurulur, ekran silinir, imleç (0, 0)
3mov ah, 02h0203h0000h0000h0000h(0, 0)AH = 02h: imleci konumla
4mov bh, 00203h0000h0000h0000h(0, 0)BH = sayfa 0
5mov dx, 0104h0203h0000h0000h0104h(0, 0)DH = 1 (satır), DL = 4 (sütun)
6int 10h0203h0000h0000h0104h(1, 4)imleç (1, 4)'e taşındı; ekran boş
7mov ah, 09h0903h0000h0000h0104h(1, 4)AH = 09h: karakter + öznitelik
8mov al, '*'092Ah0000h0000h0104h(1, 4)AL = '*' = 2Ah
9mov bl, 4Eh092Ah004Eh0000h0104h(1, 4)BL = 4Eh: kırmızı zemin, sarı yazı
10mov cx, 3092Ah004Eh0003h0104h(1, 4)CX = 3 tekrar
11int 10h092Ah004Eh0003h0104h(1, 4)(1, 4)–(1, 6) hücrelerine ***; imleç yerinde
12mov ah, 0Eh0E2Ah004Eh0003h0104h(1, 4)AH = 0Eh: teletype
13mov al, 'A'0E41h004Eh0003h0104h(1, 4)AL = 'A'
14int 10h0E41h004Eh0003h0104h(1, 5)'A' ilk yıldızın üzerine; imleç ilerledi
15mov al, 'B'0E42h004Eh0003h0104h(1, 5)AL = 'B'
16int 10h0E42h004Eh0003h0104h(1, 6)'B' ikinci yıldızın üzerine: ekranda AB*
17ret0E42h004Eh0003h0104h(1, 6)yığından 0000h → IP
18INT 20h (PSP:0000h)0E42h004Eh0003h0104h(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.

Tablo 5.2.9: AH = 13h yazma modları (AL).
ALDizginin biçimiİmleç
00hyalnız karakterler; hepsi BL özniteliğindeyerinde kalır
01hyalnız karakterler; hepsi BL özniteliğindedizginin sonuna ilerler
02hkarakter, öznitelik çiftleriyerinde kalır
03hkarakter, öznitelik çiftleridizginin 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.

Tablo 5.2.10: AH = 13h ile renkli dizgi yazan programın izlemesi.
AdımKomutAXBXCXDXBPİmleçAçıklama
1mov ax, 1301h1301h0000h0000h0000h0000h(0, 0)AH = 13h, AL = 01h (öznitelik BL'de, imleç ilerler)
2mov bx, 001Eh1301h001Eh0000h0000h0000h(0, 0)BH = 0 (sayfa), BL = 1Eh (mavi zemin, sarı yazı)
3mov cx, 71301h001Eh0007h0000h0000h(0, 0)dizgi uzunluğu 7
4mov dx, 0205h1301h001Eh0007h0205h0000h(0, 0)DH = 2, DL = 5: başlangıç konumu
5lea bp, mesaj1301h001Eh0007h0205h0112h(0, 0)BP = mesaj'ın bağıl konumu; ES = DS
6int 10h1301h001Eh0007h0205h0112h(2, 12)(2, 5)'ten başlayarak Merhaba; imleç (2, 12)
7ret1301h001Eh0007h0205h0112h(2, 12)program biter
8INT 20h (PSP:0000h)1301h001Eh0007h0205h0112h(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.

Sık yapılan hata

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.

Tablo 5.2.11: AH = 06h hizmetinin yazmaçları.
YazmaçAnlamı
ALkaydırılacak satır sayısı; 0 = pencereyi temizle
BHboşalan satırların özniteliği
CH, CLsol üst köşe (satır, sütun)
DH, DLsağ 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.

Tablo 5.2.12: Ekranı ve bir pencereyi AH = 06h ile temizleyen programın izlemesi.
AdımKomutAXBXCXDXAçıklama
1mov ax, 0600h0600h0000h0000h0000hAH = 06h (yukarı kaydır), AL = 0 (temizle)
2mov bh, 1Fh0600h1F00h0000h0000hBH = 1Fh: mavi zemin, beyaz yazı
3mov cx, 0000h0600h1F00h0000h0000hsol üst köşe (0, 0)
4mov dx, 184Fh0600h1F00h0000h184Fhsağ alt köşe (24, 79)
5int 10h0600h1F00h0000h184Fhtüm ekran mavi zemine silinir
6mov ax, 0600h0600h1F00h0000h184Fhikinci çağrı için AH, AL yeniden
7mov bh, 4Fh0600h4F00h0000h184FhBH = 4Fh: kırmızı zemin, beyaz yazı
8mov cx, 0714h0600h4F00h0714h184Fhsol üst (7, 20)
9mov dx, 103Bh0600h4F00h0714h103Bhsağ alt (16, 59)
10int 10h0600h4F00h0714h103Bh10 satır × 40 sütunluk kutu kırmızıya silinir
11ret0600h4F00h0714h103Bhprogram biter
AX0600hBH4FhCX0714hDX103BhCH,CL = (7, 20)DH,DL = (16, 59)(0,0)(24,79)
Şekil 5.2.7: İkinci çağrıdan sonra ekranın şeması: dış dikdörtgen 1Fh (mavi zemin) ile silinen 80 × 25 ekran, iç dikdörtgen 4Fh (kırmızı zemin) ile silinen (7, 20)–(16, 59) penceresidir. Renkler gerçek ekran renkleri değil, şemanın vurgu renkleridir.
Örnek 5.2.3

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.

Tanım 5.2.4

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.

41hB800:00A8 · karakter 'A'4EhB800:00A9 · öznitelikmov es:[di], ax (AX = 4E41h)düşük bayt 41h → çift adres (karakter)
Şekil 5.2.8: Bir ekran hücresi iki bayttı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.

Tablo 5.2.13: Ekran belleğine doğrudan yazan programın izlemesi.
AdımKomutAXCXDIESDFAçıklama
1mov ax, 0B800hB800h0000h0000h0700h0kesim değeri önce AX'e
2mov es, axB800h0000h0000hB800h0ES = B800h: metin ekranının kesimi
3mov di, (1*80+4)*2B800h0000h00A8hB800h0(1 × 80 + 4) × 2 = 168 = 00A8h
4mov ax, 4E41h4E41h0000h00A8hB800h0AL = 41h ('A'), AH = 4Eh (öznitelik)
5mov es:[di], ax4E41h0000h00A8hB800h0B80A8h ← 41h, B80A9h ← 4Eh; 'A' anında ekranda
6xor di, di4E41h0000h0000hB800h0DI = 0: sol üst hücre
7mov ax, 072Eh072Eh0000h0000hB800h0AL = 2Eh ('.'), AH = 07h
8mov cx, 3072Eh0003h0000hB800h0üç hücre doldurulacak
9cld072Eh0003h0000hB800h0DF = 0: DI artarak ilerler
10rep stosw072Eh0000h0006hB800h0üç kez ES:[DI] ← AX, DI += 2
11ret072Eh0000h0006hB800h0program biter
ESB800hDI0006hAX072EhCX0000hB800:0000…2E072E072E07B800:00A8414Ekarakter · öznitelik...Aekran: satır 0–1, sütun 0–5
Şekil 5.2.9: Program bitince görüntü belleği: B800:0000h'dan itibaren üç kez 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.

Sık yapılan hata

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.

x=0x=1x=2x=3x=319y=00000000100020003013Fy=10140014101420143027Fy=2028002810282028303BFy=199F8C0F8C1F8C2F8C3F9FF…………⋮⋮ofset = y·320 + x · turuncu köşegen: +141h
Şekil 5.2.10: Mod 13h'te piksel bağıl konumları. Her satır 140h bayttır; bir alt satırın aynı sütunu +140h, köşegende bir alt ve bir sağ +141h ileridedir.

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.

Örnek 5.2.4

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 piksel

Dö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ön

Neden 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
Tablo 5.2.14: A000h belleğine dört piksellik köşegen çizen programın izlemesi.
AdımKomutALCXDIESAçıklama
1mov ax, 0A000h00h0000h0000h0700hkesim değeri AX üzerinden
2mov es, ax00h0000h0000hA000hES = A000h: mod 13h görüntü belleği
3xor di, di00h0000h0000hA000hDI = 0: piksel (0, 0)
4mov al, 0Eh0Eh0000h0000hA000hrenk 0Eh (sarı)
5mov cx, 40Eh0004h0000hA000hdört piksel
6mov es:[di], al0Eh0004h0000hA000hA0000h ← 0Eh: piksel (0, 0)
7add di, 141h0Eh0004h0141hA000hbir alt satır, bir sağ sütun
8loop ciz0Eh0003h0141hA000hCX = 3 ≠ 0: ciz'e dön
9mov es:[di], al0Eh0003h0141hA000hA0141h ← 0Eh: piksel (1, 1)
12mov es:[di], al0Eh0002h0282hA000hA0282h ← 0Eh: piksel (2, 2)
15mov es:[di], al0Eh0001h03C3hA000hA03C3h ← 0Eh: piksel (3, 3)
16add di, 141h0Eh0001h0504hA000hDI = 0504h = (4, 4)'ün yeri
17loop ciz0Eh0000h0504hA000hCX = 0: döngü biter
18ret0Eh0000h0504hA000hprogram 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.

ESA000hDI0504hCX0000hAL0EhDI = 1284 → y = 4, x = 4satır başına 320 = 140h bayt+141h = bir alt, bir sağekranın sol üstü (6 × 6 piksel)
Şekil 5.2.11: Döngü bitince ekranın sol üst 6 × 6 piksellik bölgesi: (0, 0)–(3, 3) sarı, DI = 0504h (1284) yani y = 4, x = 4.

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.

Tanım 5.2.5

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.

Tablo 5.2.15: INT 16h klavye hizmetleri.
AHHizmetÇıkış
00htuş bekle ve okuAH = tarama kodu, AL = ASCII; tuş tampondan silinir
01htuş var mı? (beklemez)ZF = 1: tuş yok · ZF = 0: AX = tuş; tuş tampondan silinmez
02hShift 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.

Tablo 5.2.16: Bazı tuşların INT 16h/00h dönüş değerleri (IBM PC/AT, ABD düzeni).
TuşAH (tarama)AL (ASCII)TuşAH (tarama)AL
a / A1Eh61h / 41h↑ / ↓48h / 50h00h
102h31h← / →4Bh / 4Dh00h
Enter1Ch0DhF1 … F103Bh … 44h00h
Esc01h1BhBackspace0Eh08h
Boşluk39h20hCtrl+C2Eh03h

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:
ret

Dö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.

Tablo 5.2.17: Tuş okuyup büyük harfle yazan programın izlemesi (basılan tuşlar: Shift+o, k, Enter).
AdımKomutAXCFZFEkran (çıktı)Açıklama
1mov ah, 00000h00–AH = 00h: tuş bekle ve oku
2int 16h184Fh00–Shift+o: AH = 18h (tarama), AL = 4Fh ('O')
3cmp al, 0Dh184Fh00–4Fh − 0Dh: sonuç sıfır değil
4je bitti184Fh00–Enter değil, atlama yok
5cmp al, 'a'184Fh10–4Fh < 61h: ödünç, CF = 1
6jb yaz184Fh10–CF = 1: yaz'a atla
7mov ah, 0Eh0E4Fh10–AH = 0Eh; AL'de 'O' duruyor
8int 10h0E4Fh10Oekrana O
9jmp oku0E4Fh10Odöngü başına
11int 16h256Bh10Ok: AH = 25h, AL = 6Bh
14cmp al, 'a'256Bh00O6Bh ≥ 61h: CF = 0
15jb yaz256Bh00Oatlama yok: küçük harf olabilir
16cmp al, 'z'256Bh10O6Bh − 7Ah: ödünç, CF = 1, ZF = 0
17ja yaz256Bh10OJA, CF = 0 ve ZF = 0 ister; atlamaz
18sub al, 20h254Bh00O6Bh − 20h = 4Bh = 'K'
20int 10h0E4Bh00OKekrana K
23int 16h1C0Dh00OKEnter: AH = 1Ch, AL = 0Dh
24cmp al, 0Dh1C0Dh01OK0Dh − 0Dh = 0: ZF = 1
25je bitti1C0Dh01OKbitti'ye atla
26ret1C0Dh01OKprogram 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
ret

DX, 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.

Tablo 5.2.18: AH = 01h ile tuş yoklayan döngünün izlemesi (üçüncü yoklamada x basılı).
AdımKomutAXDXZFAçıklama
1xor dx, dx0000h0000h1iş sayacı sıfırlanır
2inc dx0000h0001h0arka plan işi: 1
3mov ah, 01h0100h0001h0AH = 01h: tuş var mı?
4int 16h0100h0001h1tampon boş: ZF = 1
5jz bekle0100h0001h1ZF = 1: bekle'ye dön
6inc dx0100h0002h0arka plan işi: 2
8int 16h0100h0002h1yine tuş yok
10inc dx0100h0003h0arka plan işi: 3
12int 16h2D78h0003h0x var: ZF = 0, AX = 2D78h; tuş tamponda kalır
13jz bekle2D78h0003h0ZF = 0: döngüden çık
14mov ah, 00h0078h0003h0AH = 00h: tuşu al
15int 16h2D78h0003h0aynı tuş okunur ve tampondan silinir
16ret2D78h0003h0program 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.

Sık yapılan hata

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.

Tablo 5.2.19: Sık kullanılan INT 21h hizmetleri.
AHHizmetGirişÇıkış
01hkarakter oku ve yansıt–AL = karakter
02hkarakter yazDL = karakterAL = DL
07h / 08hkarakter oku, yansıtmadan–AL (08h Ctrl+C'yi denetler)
09hdizgi yazDS:DX → '$' ile biten dizgiAL = 24h
0Ahtamponlu satır okuDS:DX → tampon[tampon+1] = sayı, tampon+2 = metin
2Ahtarihi al–CX = yıl, DH = ay, DL = gün, AL = haftanın günü (0 = Pazar)
2Chsaati al–CH = saat, CL = dakika, DH = saniye, DL = salise
2Bh / 2Dhtarihi / saati ayarla2Ah / 2Ch ile aynı yazmaçlarAL = 00h başarılı
4Chprogramı sonlandırAL = çı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.

Tablo 5.2.20: INT 10h/0Eh ile INT 21h/02h karşılaştırması.
ÖzellikBIOS · INT 10h, AH = 0EhDOS · INT 21h, AH = 02h
KarakterAL'deDL'de
Gereken yazılımyalnız video BIOS'u; açılış (boot) kodunda da çalışırDOS yüklü olmalı
Yönlendirmeyok; hep ekranavar; dosyaya, yazıcıya
Renkgrafik modda BL ileyok
Dönüşte ALkorunurAL = DL
Ctrl+Break denetimiyokvar

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
Tablo 5.2.21: Karakter okuyup bir sonrakini yeni satıra yazan programın izlemesi (basılan tuş: k). ⏎ CR, ↵ CR LF demektir.
AdımKomutAXBXDXEkran (çıktı)Açıklama
1mov ah, 01h0100h0000h0000h–AH = 01h: oku ve yansıt
2int 21h016Bh0000h0000hkk: AL = 6Bh; ekranda k
3mov bl, al016Bh006Bh0000hkokunan karakter BL'de saklanır
4mov ah, 02h026Bh006Bh0000hkAH = 02h: DL'yi yaz
5mov dl, 0Dh026Bh006Bh000DhkDL = 0Dh (CR)
6int 21h020Dh006Bh000Dhk⏎imleç satır başına; AL = 0Dh
7mov dl, 0Ah020Dh006Bh000Ahk⏎DL = 0Ah (LF)
8int 21h020Ah006Bh000Ahk↵imleç alt satıra; AL = 0Ah
9inc bl020Ah006Ch000Ahk↵BL = 6Ch ('l')
10mov dl, bl020Ah006Ch006Chk↵DL = 'l'
11int 21h026Ch006Ch006Chk↵lekrana l; AL = 6Ch
12ret026Ch006Ch006Chk↵lprogram 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.

Tanım 5.2.6

'$' 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.

Tablo 5.2.22: AH = 09h ile iki dizgi yazan programın izlemesi.
AdımKomutAXDXEkran (çıktı)Açıklama
1mov dx, offset msg10000h010Dh–DS:DX → msg1 (010Dh)
2mov ah, 09h0900h010Dh–AH = 09h
3int 21h0924h010DhMerhaba, 8086!↵'$'a kadar yazılır; AL = 24h
4mov dx, offset msg20924h011EhMerhaba, 8086!↵DX → msg2 (011Eh)
5int 21h0924h011EhMerhaba, 8086!↵Gule guleAH hâlâ 09h: ikinci dizgi
6ret0924h011EhMerhaba, 8086!↵Gule guleprogram 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.

Sık yapılan hata

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.

Tanım 5.2.7

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.

0Ah+003h+1'A'+2'l'+3'i'+40Dh+5?+6en fazlaokunankarakterler …DS:DX →
Şekil 5.2.12: Enter'dan sonra 0Ah tamponu: +0 kapasite (0Ah), +1 okunan sayı (03h), +2'den itibaren metin ve sonunda 0Dh.

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 $'
Tablo 5.2.23: Ad okuyup selam veren programın izlemesi (yazılan: Ali, Enter).
AdımKomutAXBXDXEkran (çıktı)Açıklama
1mov dx, offset tampon0000h0000h011Fh–DS:DX → tampon (011Fh)
2mov ah, 0Ah0A00h0000h011Fh–AH = 0Ah: satır oku
3int 21h0A00h0000h011FhAli⏎tampon = 0Ah, 03h, 'A', 'l', 'i', 0Dh
4mov bl, [tampon+1]0A00h0003h011FhAli⏎BL = [0120h] = 3
5mov bh, 00A00h0003h011FhAli⏎BX = 0003h
6mov byte ptr tampon[bx+2], '$'0A00h0003h011FhAli⏎[011Fh + 3 + 2] = [0124h] ← '$'
7mov dx, offset selam0A00h0003h012BhAli⏎DX → selam (012Bh)
8mov ah, 09h0900h0003h012BhAli⏎AH = 09h
9int 21h0924h0003h012BhAli⏎↵Merhaba CR LF ve Merhaba yazılır
10lea dx, [tampon+2]0924h0003h0121hAli⏎↵Merhaba DX = 0121h: metnin başı
11int 21h0924h0003h0121hAli⏎↵Merhaba AliAli yazılır
12ret0924h0003h0121hAli⏎↵Merhaba Aliprogram 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.

Örnek 5.2.5

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.

Sık yapılan hata

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.

Tablo 5.2.24: INT 21h/2Ah ve 2Ch dönüş değerleri.
YazmaçAH = 2Ah (tarih)AH = 2Ch (saat)
CX / CHCX = yıl (ör. 07EAh = 2026)CH = saat (0–23)
CL(CX'in parçası)CL = dakika (0–59)
DHay (1–12)saniye (0–59)
DLgün (1–31)salise (0–99)
ALhaftanı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.

Örnek 5.2.6

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.

Tablo 5.2.25: Gün adını tablodan yazan programın izlemesi (tarih 7 Ocak 2026, Çarşamba).
AdımKomutAXBXCXDXEkran (çıktı)Açıklama
1mov ah, 2Ah2A00h0000h0000h0000h–AH = 2Ah: tarihi al
2int 21h2A03h0000h07EAh0107h–CX = 07EAh (2026), DH = 01h (ay), DL = 07h (gün), AL = 3 (Çarşamba)
3mov ah, 00003h0000h07EAh0107h–AX = 0003h
4mov bl, 40003h0004h07EAh0107h–her ad 4 bayt
5mul bl000Ch0004h07EAh0107h–AX = 3 × 4 = 12 = 000Ch
6mov dx, offset gunler000Ch0004h07EAh0114h–DX = gunler = 0114h; tarih silindi
7add dx, ax000Ch0004h07EAh0120h–DX = 0120h: Car$
8mov ah, 09h090Ch0004h07EAh0120h–AH = 09h
9int 21h0924h0004h07EAh0120hCarekrana Car
10ret0924h0004h07EAh0120hCarprogram biter
AL0ChBL04hAX000ChDX0120hgunler (0114h): 7 × 4 baytPaz$+0Pzt$+4Sal$+8Car$+12Per$+16Cum$+20Cmt$+24DXekran▌
Şekil 5.2.13: 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.

Sık yapılan hata

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.

Tablo 5.2.26: Saati SS:DD biçiminde yazan programın izlemesi (saat 14:35:07,42).
AdımKomutAXBXCXDXSPEkran (çıktı)Açıklama
1mov ah, 2Ch2C00h0000h0000h0000hFFFEh–AH = 2Ch: saati al
2int 21h2C00h0000h0E23h072AhFFFEh–CH = 0Eh (14), CL = 23h (35), DH = 07h, DL = 2Ah (42)
3mov al, ch2C0Eh0000h0E23h072AhFFFEh–AL = saat
4call yaz22C0Eh0000h0E23h072AhFFFCh–dönüş adresi 0109h yığında
5aam0104h0000h0E23h072AhFFFCh–14 = 1 × 10 + 4: AH = 1, AL = 4
6add ax, 3030h3134h0000h0E23h072AhFFFCh–iki basamak ASCII'ye: '1', '4'
7mov bx, ax3134h3134h0E23h072AhFFFCh–BX'te saklanır; 02h AL'yi bozar
8mov dl, bh3134h3134h0E23h0731hFFFCh–DL = '1'
9mov ah, 02h0234h3134h0E23h0731hFFFCh–AH = 02h
10int 21h0231h3134h0E23h0731hFFFCh1ekrana 1; AL = 31h
11mov dl, bl0231h3134h0E23h0734hFFFCh1DL = '4'
12int 21h0234h3134h0E23h0734hFFFCh14ekrana 4
13ret0234h3134h0E23h0734hFFFEh140109h'ye dönüş
14mov dl, ':'0234h3134h0E23h073AhFFFEh14DL = ':'
16int 21h023Ah3134h0E23h073AhFFFEh14:ekrana :
17mov al, cl0223h3134h0E23h073AhFFFEh14:AL = dakika = 23h; CL bozulmadı
18call yaz20223h3134h0E23h073AhFFFCh14:dönüş adresi 0114h
19aam0305h3134h0E23h073AhFFFCh14:35 = 3 × 10 + 5
20add ax, 3030h3335h3134h0E23h073AhFFFCh14:'3', '5'
24int 21h0233h3335h0E23h0733hFFFCh14:3ekrana 3
26int 21h0235h3335h0E23h0735hFFFCh14:35ekrana 5
27ret0235h3335h0E23h0735hFFFEh14:350114h'ye dönüş
28ret0235h3335h0E23h0735h0000h14:35yığından 0000h; SP = 0000h
29INT 20h (PSP:0000h)0235h3335h0E23h0735h0000h14:35INT 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.

Tablo 5.2.27: INT 1Ah hizmetleri.
AHİşlevDönüş
00htık sayacını okuCX:DX = gece yarısından beri tık sayısı, AL = gün döndü bayrağı
02hRTC saatini okuCH = saat, CL = dakika, DH = saniye (BCD), DL = yaz saati; CF = 1: hata
04hRTC tarihini okuCH = yüzyıl, CL = yıl, DH = ay, DL = gün (BCD); CF = 1: hata
Tanım 5.2.8

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.

Tablo 5.2.28: Paketli BCD 35h'nin ASCII'ye çevrilmesi.
AdımİşlemSonuç
135h = 0011 0101byüksek nibble 3, düşük nibble 5
2shr dl, cl (CL = 4)0000 0011b = 03h
3and dl, 0Fh0000 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.

Örnek 5.2.7

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
ret

Program ö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.

Tablo 5.2.29: RTC saatini SS:DD:ss biçiminde yazan programın izlemesi (saat 14:35:07).
AdımKomutAXBXCXDXSPCFEkran (çıktı)Açıklama
1mov ah, 02h0200h0000h0000h0000hFFFEh0–AH = 02h: RTC saatini oku
2int 1Ah0200h0000h1435h0700hFFFEh0–CH = 14h, CL = 35h, DH = 07h (paketli BCD); DL = 00h
3jc son0200h0000h1435h0700hFFFEh0–CF = 0: atlama yok
4mov bl, cl0200h0035h1435h0700hFFFEh0–dakika BL'de saklanır
5mov cl, 40200h0035h1404h0700hFFFEh0–CL = 4: kaydırma sayısı
6mov bh, ch0200h1435h1404h0700hFFFEh0–BH = saat = 14h
7call bcdyaz0200h1435h1404h0700hFFFCh0–doğrudan bcdyaz
8mov dl, bh0200h1435h1404h0714hFFFCh0–DL = 14h = 0001 0100b
9shr dl, cl0200h1435h1404h0701hFFFCh0–4 bit sağa: 01h
10add dl, 30h0200h1435h1404h0731hFFFCh0–DL = 31h = '1'
12int 21h0231h1435h1404h0731hFFFCh01ekrana 1
13mov dl, bh0231h1435h1404h0714hFFFCh01DL = 14h yeniden
14and dl, 0Fh0231h1435h1404h0704hFFFCh01üst 4 bit silinir: 04h
15add dl, 30h0231h1435h1404h0734hFFFCh01DL = 34h = '4'
16int 21h0234h1435h1404h0734hFFFCh014ekrana 4
17ret0234h1435h1404h0734hFFFEh014dönüş
18mov bh, bl0234h3535h1404h0734hFFFEh014BH = dakika = 35h
19call ikinokta0234h3535h1404h0734hFFFCh014ikinokta girişi
22int 21h023Ah3535h1404h073AhFFFCh014:ekrana :
23mov dl, bh023Ah3535h1404h0735hFFFCh014:bcdyaz'a kendiliğinden geçilir
27int 21h0233h3535h1404h0733hFFFCh014:3ekrana 3
31int 21h0235h3535h1404h0735hFFFCh014:35ekrana 5
32ret0235h3535h1404h0735hFFFEh014:35dönüş
33mov bh, dh0235h0735h1404h0735hFFFEh014:35BH = saniye = 07h
37int 21h023Ah0735h1404h073AhFFFCh014:35:ekrana :
42int 21h0230h0735h1404h0730hFFFCh014:35:0ekrana 0
46int 21h0237h0735h1404h0737hFFFCh014:35:07ekrana 7
47ret0237h0735h1404h0737hFFFEh014:35:07dönüş
48ret0237h0735h1404h0737h0000h014:35:07program 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.

Sık yapılan hata

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.

Tablo 5.2.30: BIOS veri alanından seçilmiş konumlar.
AdresBoyutİçerik
0040:0010sözcükdonanım listesi (INT 11h'nin döndürdüğü değer)
0040:0013sözcüktaban bellek, KB (INT 12h)
0040:0017baytklavye bayrakları: bit 0 sağ Shift, 1 sol Shift, 2 Ctrl, 3 Alt, 4 Scroll Lock, 5 Num Lock, 6 Caps Lock, 7 Insert
0040:001Asözcüktampon başı: sıradaki okunacak tuşun bağıl konumu
0040:001Csözcüktampon sonu: sıradaki boş yerin bağıl konumu (baş = son → tampon boş)
0040:001E–003D32 baytklavye tamponu: 16 sözcük (ASCII + tarama kodu), dairesel; en çok 15 tuş
0040:0049baytgeçerli video modu (03h, 13h …)
0040:004Asözcükekrandaki sütun sayısı (mod 03h'te 80)
0040:00508 sözcük8 sayfanın imleç konumu (düşük bayt sütun, yüksek bayt satır)
0040:006Cçift sözcüktık sayacı: gece yarısından beri ≈ 18,2 Hz'lik kesme sayısı
0040:0070baytgece 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ı.

Örnek 5.2.8

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_bos

Bir tıkın süresi zamanlayıcının bölme oranından hesaplanır. Tablo 5.2.31 değerleri verir.

Tablo 5.2.31: Tık sayacının zaman değerleri.
BüyüklükHesapDeğer
Tık sıklığı1 193 182 Hz ÷ 65 53618,2065 Hz
Bir tık65 536 ÷ 1 193 182 s≈ 54,9 ms
18 tık18 × 54,925 ms≈ 0,989 s
5 saniye5 × 18,2065≈ 91 tık
Bir günsayacın sıfırlandığı değer1800B0h = 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.

Sık yapılan hata

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).

Tablo 5.2.32: Programı sonlandırmanın üç yolu.
YöntemNasıl çalışır?Nerede?
retCOM 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 20hDOS programı sonlandırır; CS'nin PSP kesimini göstermesi gerekir.COM
mov ax, 4C00h
int 21h
AL'deki çıkış koduyla sonlandırır, açık dosyaları kapatır.COM ve EXE · önerilen
Tanım 5.2.9

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 basla

EXE 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.

Tablo 5.2.33: EXE şablonunun izlemesi (kesim değerleri emu8086 yerleşimine göre).
AdımKomutAXDSDXEkran (çıktı)Açıklama
1mov ax, @data0720h0700h0000h–@data = veri kesimi 0720h; DS hâlâ PSP'de
2mov ds, ax0720h0720h0000h–DS = 0720h: veri kesimi
3mov dx, offset msg0720h0720h0000h–msg veri kesiminin başında
4mov ah, 09h0920h0720h0000h–AH = 09h
5int 21h0924h0720h0000hMerhaba0720:0000'dan '$'a kadar
6mov ax, 4C00h4C00h0720h0000hMerhabaAH = 4Ch, AL = 00h
7int 21h4C00h0720h0000hMerhabaçıkış kodu 0 ile DOS'a dönüş
DS0720hAX0720hDX0000h0700h PSP (256 bayt)0710h yığın (.stack 100h)0720h veri: 'Merhaba$'DS0721h kodCSekran▌
Şekil 5.2.14: 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
ret

Sayı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.

BL0706050413121100maske10000000AND → 00000000ZF = 1 (bit 7 = 0)
Şekil 5.2.15: 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.

önce0706050413121100sonra00011100CF0bit 7 → CFsağdan 0 girer
Şekil 5.2.16: 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).

Tablo 5.2.34: Hesaplama kısmının izlemesi (bayraklar her komuttan sonra).
AdımKomutAHDLBLCXZFCFPFEkran (çıktı)Açıklama
1mov al, 500h00h00h0000h000–AL = 05h; MOV bayrak değiştirmez
2mov bl, 1000h00h0Ah0000h000–BL = 0Ah
3add bl, al00h00h0Fh0000h001–0Ah + 05h = 0Fh; dört 1 biti: PF = 1
4sub bl, 100h00h0Eh0000h000–0Fh − 1 = 0Eh; üç 1 biti: PF = 0
5mov cx, 800h00h0Eh0008h000–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.

Tablo 5.2.35: Döngünün 1. ve 5. turları adım adım (5. turda bit 7 = 1).
AdımKomutAHDLBLCXZFCFPFEkran (çıktı)Açıklama
6mov ah, 202h00h0Eh0008h000–tur 1: AH = 2
7mov dl, '0'02h30h0Eh0008h000–varsayılan '0'
8test bl, 10000000b02h30h0Eh0008h101–0Eh AND 80h = 0: ZF = 1
9jz zero02h30h0Eh0008h101–ZF = 1: zero'ya atla
10int 21h02h30h0Eh0008h1010ekrana 0
11shl bl, 102h30h1Ch0008h0000BL = 1Ch; çıkan bit 0
12loop print02h30h1Ch0007h0000CX = 7 ≠ 0: print'e
34mov ah, 202h30hE0h0004h0000000tur 5: AH = 2
35mov dl, '0'02h30hE0h0004h0000000varsayılan '0'
36test bl, 10000000b02h30hE0h0004h0000000E0h AND 80h = 80h: ZF = 0
37jz zero02h30hE0h0004h0000000atlama yok
38mov dl, '1'02h31hE0h0004h0000000DL = '1'
39int 21h02h31hE0h0004h00000001ekrana 1
40shl bl, 102h31hC0h0004h01100001BL = C0h; çıkan bit CF = 1
41loop print02h31hC0h0003h01100001CX = 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.

Tablo 5.2.36: Sekiz turun özeti (her satır, o turun LOOP komutundan sonraki durum).
TurBL (TEST öncesi)Bit 7YazılanBL (SHL sonrası)CFCXEkran
10Eh = 00001110001Ch00007h0
21Ch = 000111000038h00006h00
338h = 001110000070h00005h000
470h = 0111000000E0h00004h0000
5E0h = 1110000011C0h10003h00001
6C0h = 110000001180h10002h000011
780h = 100000001100h10001h0000111
800h = 000000000000h00000h00001110

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_
Örnek 5.2.9

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.

Tablo 5.2.37: Mini menü programının izlemesi (basılan tuşlar: 1, q).
AdımKomutAXDXZFEkran (çıktı)Açıklama
1mov dx, offset menu0000h0121h0–DX → menü metni
2mov ah, 09h0900h0121h0–AH = 09h
3int 21h0924h0121h0↵1:Selam q:Cikis CR LF ve menü yazılır
4mov ah, 01h0124h0121h0↵1:Selam q:Cikis AH = 01h: oku ve yansıt
5int 21h0131h0121h0↵1:Selam q:Cikis 11: AL = 31h
6cmp al, 'q'0131h0121h0↵1:Selam q:Cikis 131h − 71h ≠ 0: ZF = 0
7je cikis0131h0121h0↵1:Selam q:Cikis 1atlama yok
8cmp al, '1'0131h0121h1↵1:Selam q:Cikis 131h − 31h = 0: ZF = 1
9jne goster0131h0121h1↵1:Selam q:Cikis 1eşit: atlama yok
10mov dx, offset selam0131h0134h1↵1:Selam q:Cikis 1DX → selam
12int 21h0924h0134h1↵1:Selam q:Cikis 1↵Selam!yeni satıra Selam!
13jmp goster0924h0134h1↵1:Selam q:Cikis 1↵Selam!menüye dön
16int 21h0924h0121h1↵1:Selam q:Cikis 1↵Selam!↵1:Selam q:Cikis menü yeniden yazılır
18int 21h0171h0121h1↵1:Selam q:Cikis 1↵Selam!↵1:Selam q:Cikis qq: AL = 71h
19cmp al, 'q'0171h0121h1↵1:Selam q:Cikis 1↵Selam!↵1:Selam q:Cikis qeşit: ZF = 1
20je cikis0171h0121h1↵1:Selam q:Cikis 1↵Selam!↵1:Selam q:Cikis qcikis'a atla
21mov ax, 4C00h4C00h0121h1↵1:Selam q:Cikis 1↵Selam!↵1:Selam q:Cikis qAH = 4Ch, AL = 00h
22int 21h4C00h0121h1↵1:Selam q:Cikis 1↵Selam!↵1:Selam q:Cikis qçıkış kodu 0 ile DOS'a dönüş

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 q

Veri, 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.

Tablo 5.2.38: Kesme hizmetleriyle yapılan sık hatalar.
HataSonuçDüzeltme
'$' unutulduINT 21h/09h belleği '$' bulana kadar yazar; ekrana çöp dolardizginin sonuna '$'
DS ayarlanmadı (EXE)DX doğru ama kesim yanlış; PSP yazılırmov ax, @data · mov ds, ax
AL'nin bozulması02h ve 09h AL'yi değiştirir; okunan karakter kaybolurdeğeri başka yazmaçta saklamak
09h sonrası imleçINT 10h/09h imleci ilerletmez; sonraki yazı üstüne gelirimleci 02h ile taşımak
13h'te DS:DXBIOS dizgi hizmeti adresi ES:BP'de beklerlea bp, dizgi; DX konum
0Ah tamponukapasite yazılmamış ya da metin tampon+0'dan okunmuşbayt 0 = kapasite; metin tampon+2'de
Yalnız LFimleç alt satıra iner, satır başına gelmezCR + LF (0Dh, 0Ah)
Sonlandırma yokveriler komut olarak yürütülürRET (COM) ya da INT 21h/4Ch
Sık yapılan hata

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
ret

Her 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
ret

Gü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 n ile, 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 @data ile kendisi ayarlar.

5.2.12Kavram listesi

5.2.13Kendini Dene

  1. 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ı.

  2. 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.

  3. 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.

  4. 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 0D olur: kapasite, okunan sayı 3, 'a', 'b', 'c' ve Enter.

  5. mov ah, 02h, mov dl, 'Z', int 21h komutları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.

  6. 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.

  7. 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.

  8. 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.

  9. 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.

  10. Bir EXE programı MOV AX, 4C00h · INT 21h yerine RET ile 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

  1. R. Brown, Ralf Brown's Interrupt List (INT 10h, 16h, 21h ayrıntılı başvuru).
  2. IBM, Personal Computer AT Technical Reference, BIOS bölümü, 1984.
  3. P. Abel, IBM PC Assembly Language and Programming, 5. baskı, Prentice Hall, 2001.
  4. B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009.
  5. emu8086 yardım belgeleri: supported interrupt functions.
  6. Ş. Ç. Öztürk, O. Ergin, Intel 8086 ile Mikroişlemci Programlamaya Giriş, 2009.
  7. 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.