Mikroişlemciler · Ders Notu

Bölüm 4.1: Bellek Erişimi

Bir 8086 programının yaptığı işlerin çoğu, bellekten bir değeri yazmaca almak ya da yazmaçtaki bir değeri belleğe geri koymaktır. Toplama, karşılaştırma, ekrana yazı yazma ve bir diziyi gezme bu taşımalar olmadan yapılamaz. İşlemcinin bellekte hangi bayta ulaşacağını komutun içindeki köşeli parantez belirler. Bu not, köşeli parantez içine neyin yazılabileceğini, yani adresleme modlarını anlatır. Taban ve indis yazmaçlarından, yer değiştirmeden bir etkin adres hesaplanır. Etkin adres bir kesim yazmacıyla birleşir ve adres yoluna çıkan 20 bitlik fiziksel adres olur. Hangi kesimin seçildiği, aynı bağıl konumun bambaşka bir bayta gitmesine yol açabilir. Not bu hesabı her iki yönde de yapar ve kesim önekiyle varsayılan kesimin nasıl değiştirildiğini gösterir. Ardından erişimin boyutu (bayt mı sözcük mü), bayt sırası ve MOV ile XCHG komutlarının kuralları gelir. Örnek programlar adım adım, yazmaç ve bellek düzeyinde izlenir; son örnek, renkli metin ekranının belleğine doğrudan bir harf yazar.

Öğrenme çıktıları

Geçerli bellek işleneni kurmak
BX, BP, SI, DI ve yer değiştirmeyle 8086'nın 24 bellek adresleme biçimini oluşturmak; geçersiz birleşimleri nedeniyle ayırt etmek.
Adresleme modlarını adlandırmak
Anlık, yazmaç, doğrudan, yazmaç dolaylı, tabanlı, indisli ve tabanlı-indisli modları, ayrıca dizgi, G/Ç ve göreceli modları örnekleriyle tanımak; bir veri yapısına uygun modu seçmek.
Adres hesaplamak
Etkin adresi 16 bitlik sarmayla hesaplamak; kesim:bağıl konumdan fiziksel adrese ve fiziksel adresten olası kesim:bağıl konum çiftlerine geçmek; adres hattı sayısından bellek kapasitesini bulmak.
Kesimi doğru seçmek
Varsayılan kesim kuralını (BP varsa SS, yoksa DS) uygulamak; kesim önekinin makine koduna etkisini ve BP ile veriye erişmenin tuzağını açıklamak.
Boyut ve bayt sırası
byte ptr ve word ptr ile erişim boyutunu belirtmek; little-endian düzende sözcüklerin bellekteki yerleşimini okumak; sözcük dizisinde indisi bayt uzaklığına çevirmek.
MOV ve XCHG ile program izlemek
Geçerli işlenen birleşimlerini ayırt etmek; kopyalama, takas ve video belleğine yazma programlarını yazmaç, bellek ve IP düzeyinde adım adım izlemek.

4.1.1Bellek işlenenleri

4.1.1.1Köşeli parantez ve adres yazmaçları

8086'nın on dört yazmacı vardır ve bunların yalnız sekizi genel işlerde kullanılır. Bir programın verisi ise çoğunlukla bellekte durur: değişkenler, diziler, tablolar, ekranın içeriği, yığın. İşlemci bu verilerle çalışmak için her seferinde belleğe gider, istediği baytı ya da sözcüğü okur, işini bitirince sonucu belleğe geri yazar. Bu yüzden bir komut kümesini öğrenmenin ilk adımı, komutun bellekteki hangi hücreyi kastettiğini nasıl söylediğini öğrenmektir.

Assembly dilinde bir bellek hücresi köşeli parantezle gösterilir. MOV AX, BX komutu BX'in içindeki sayıyı AX'e kopyalar. MOV AX, [BX] komutu ise BX'teki sayıyı bir adres olarak kullanır; o adresteki sözcüğü bellekten okuyup AX'e koyar. Köşeli parantez, “içindekinin gösterdiği yer” anlamına gelir. C dilindeki işaretçi gösterimiyle karşılaştırılırsa BX bir işaretçinin kendisi, [BX] ise *p gibidir.

8086'da köşeli parantez içine her yazmaç yazılamaz. Bellek adresi tutabilen yalnız dört yazmaç vardır: BX, BP, SI ve DI. Bunlardan BX ile BP taban yazmacı (base register), SI ile DI indis yazmacı (index register) diye anılır. Taban yazmacı çoğunlukla bir veri bloğunun, örneğin bir dizinin ya da bir kaydın başlangıç adresini tutar. İndis yazmacı bu bloğun içindeki konumu sayar. Bu dört yazmaca bir de komutun içinde yazılı sabit bir sayı eklenebilir. Sabit sayıya yer değiştirme (displacement) denir.

Bu kısıtın kaynağı donanımdır. Komutun makine kodunda bellek işleneninin nasıl hesaplanacağını yalnız üç bitlik bir alan anlatır. Üç bit sekiz seçenek demektir ve 8086'nın tasarımcıları bu sekiz seçeneği BX, BP, SI ve DI'nin en kullanışlı birleşimlerine ayırmıştır. AX, CX, DX ve SP bu listede yoktur. Bu yüzden MOV AL, [CX] gibi bir yazım ne kadar doğal görünse de assembler onu reddeder; işlemcinin böyle bir adres üretecek devresi yoktur.

Tanım 4.1.1

Bir komutun işleneninin nerede bulunduğunu ve adresinin nasıl hesaplanacağını belirleyen kurala adresleme modu (addressing mode) denir. 8086'da bir bellek işleneninin adresi köşeli parantez içinde yazılır. Adres üç parçanın toplamıdır: bir taban yazmacı (BX ya da BP), bir indis yazmacı (SI ya da DI) ve bir yer değiştirme. Bu üç parçanın her biri isteğe bağlıdır; ama en az biri bulunmalıdır.

4.1.1.2Yirmi dört birleşim

Taban, indis ve yer değiştirme parçalarının izin verilen bütün birleşimleri Tablo 4.1.1'te toplanmıştır. Tablonun satırları yazmaç kısmını, sütunları yer değiştirmenin boyutunu gösterir. d8 8 bitlik, d16 16 bitlik bir yer değiştirme demektir.

Tablo 4.1.1: 8086'nın 24 bellek adresleme biçimi. Satır yazmaç kısmını, sütun yer değiştirmenin boyutunu belirler.
Yalnız yazmaç(lar)+ d8+ d16
[BX + SI][BX + SI + d8][BX + SI + d16]
[BX + DI][BX + DI + d8][BX + DI + d16]
[BP + SI][BP + SI + d8][BP + SI + d16]
[BP + DI][BP + DI + d8][BP + DI + d16]
[SI][SI + d8][SI + d16]
[DI][DI + d8][DI + d16]
d16 (doğrudan adres)[BP + d8][BP + d16]
[BX][BX + d8][BX + d16]

Tablodaki sekiz satır, makine kodundaki üç bitlik alanın sekiz değerine karşılık gelir. Bu alanın adı R/M'dir ve komutun ikinci baytı olan ModR/M baytının en düşük üç bitinde durur. Aynı baytın en yüksek iki biti MOD alanıdır; tablonun hangi sütununun kullanılacağını o seçer. MOD = 00 yer değiştirme yok, MOD = 01 d8 var, MOD = 10 d16 var demektir. MOD = 11 ise işlenenin bellek değil yazmaç olduğunu gösterir. Üç sütun ile sekiz satırın çarpımı 24 eder; 8086'nın bütün bellek adresleme biçimleri bu 24 hücrededir.

Bir satırda tuhaflık göze çarpar. Yedinci satırın ilk hücresinde [BP] yoktur; yerine d16, yani yalnız sabit bir adres vardır. Tasarımcılar R/M = 110 ve MOD = 00 birleşimini doğrudan adreslemeye ayırmıştır: MOV AL, [1234h] gibi bir komutun adresi bu kodla yazılır. Yer değiştirmesiz [BP] için kod kalmamıştır. Programcı MOV AL, [BP] yazarsa assembler bunu sessizce [BP + 0] olarak, yani MOD = 01 ve d8 = 00 ile kodlar. Komut bir bayt uzar ama doğru çalışır. Tablo 4.1.2 birkaç komutun assembler'ın ürettiği makine kodunu gösterir.

Tablo 4.1.2: Aynı MOV AL, … komutunun farklı bellek işlenenleriyle makine kodu. İkinci bayt ModR/M baytıdır.
KomutMakine koduMODR/MUzunluk
MOV AL, [BX+SI]8A 00000002 bayt
MOV AL, [BX+DI]8A 01000012 bayt
MOV AL, [BP+SI]8A 02000102 bayt
MOV AL, [BP+DI]8A 03000112 bayt
MOV AL, [SI]8A 04001002 bayt
MOV AL, [DI]8A 05001012 bayt
MOV CL, [1234h]8A 0E 34 12001104 bayt
MOV AL, [BX]8A 07001112 bayt
MOV AL, [BP]8A 46 00011103 bayt
MOV AL, [BX+5]8A 47 05011113 bayt
MOV AL, [BX+128]8A 87 80 00101114 bayt

Tablodaki 8A işlem kodu “bir baytı bellekten ya da yazmaçtan 8 bitlik bir yazmaca taşı” demektir. ModR/M baytının ortadaki üç biti (REG alanı) hedef yazmacı seçer: AL için 000, CL için 001. Örneğin 0E = 00 001 110 bitleri MOD = 00, REG = 001 (CL), R/M = 110 (doğrudan adres) olarak okunur. MOV CL, [1234h] bu yüzden dört bayttır: işlem kodu, ModR/M ve iki baytlık adres. Adres, 8086'nın bütün çok baytlı sayıları gibi düşük bayt önce yazılmıştır: 34 12. Doğrudan adresli bir komut AL ya da AX'e yükleme yapıyorsa assembler daha kısa bir özel biçim seçer: MOV AL, [1234h] komutu A0 34 12 diye üç baytla kodlanır.

4.1.1.3Birleştirme kuralı

Tablonun yapısı birkaç basit kurala indirgenebilir. Bu kurallar ezberlendiğinde tabloya bakmadan bir yazımın geçerli olup olmadığı söylenebilir. Şekil 4.1.1 kuralı üç sütunlu bir seçim olarak gösterir: her sütundan en çok bir öge alınır.

TabanBXBPyokİndisSIDIyokYer değiştirmed8d16yok++her sütundan en fazla bir seçim · BP seçilirse kesim SS, değilse DS
Şekil 4.1.1: Geçerli bir bellek işleneni, taban (BX, BP ya da hiçbiri), indis (SI, DI ya da hiçbiri) ve yer değiştirme (d8, d16 ya da hiçbiri) sütunlarının her birinden en çok bir seçimle kurulur.
Tanım 4.1.2

Birleştirme kuralı. Bir bellek işleneninde en çok bir taban yazmacı (BX ya da BP) ve en çok bir indis yazmacı (SI ya da DI) bulunur. Bunlara en çok bir yer değiştirme eklenir. BX ile BP, SI ile DI aynı adreste bir arada kullanılamaz. Parçaların yazılış sırası önemsizdir.

Varsayılan kesim kuralı. Adreste BP varsa erişim SS (yığın) kesimine, yoksa DS (veri) kesimine yapılır.

Kesim kavramının özü şudur: 8086 belleği 64 KB'lık pencerelerle görür ve her erişimde hangi pencerenin kullanılacağını bir kesim yazmacı söyler. Veri için DS, yığın için SS kullanılır. BP yığındaki verilere erişmek için tasarlandığından onunla kurulan adresler kendiliğinden SS penceresine gider. Sunumdaki dört örnek bu kuralları uygular:

  • [BX+5]: taban + d8. BP yok, kesim DS.
  • [BX+SI]: taban + indis. Kesim DS.
  • [DI+BX-4]: assembler bunu [BX+DI-4] olarak okur. Sıra önemsizdir; makine kodu 8A 41 FC'dir. Burada FC, −4'ün 8 bitlik ikiye tümleyenidir. Kesim DS.
  • [BP+SI+300]: taban + indis + d16. 300, −128…127 aralığına sığmadığı için 16 bitlik yer değiştirme gerekir. Adreste BP olduğundan kesim SS.

4.1.1.4Yer değiştirme

Yer değiştirme, adres hesabına eklenen ve komutun makine kodunun içinde duran işaretli bir sabittir. 8 bitlik biçimi (d8) −128 ile +127 arasındaki değerleri, 16 bitlik biçimi (d16) −32 768 ile +32 767 arasındaki değerleri taşır. 16 bitlik toplamada −1 ile FFFFh aynı sonucu verdiğinden d16 aslında 0000h–FFFFh aralığının tamamını kapsar. Örnek değerler: d8 için 22, 55h, −1; d16 için 300, 5517h, −259.

Yer değiştirmenin kaynağı ya bir sayıdır ya da bir değişkenin bağıl konumudur. [BX + dizi] yazıldığında assembler dizi adının kesim içindeki adresini, yani bağıl konumunu yer değiştirme olarak koyar. Yazımda birden fazla sabit varsa assembler bunları derleme sırasında tek bir sayıda toplar: [BX + 2 + 3], [BX + 5] ile aynı komuttur. Sabit köşeli parantezin içinde ya da dışında yazılabilir; [BX+5], 5[BX] ve [BX]+5 yazımlarının üçü de 8A 47 05 baytlarını üretir. dizi[SI] gibi C'ye benzeyen yazım bu esneklikten gelir. Sabit negatif de olabilir: [SI-1] komutu SI'nın gösterdiği baytın bir öncesine erişir ve 8A 44 FF olarak kodlanır.

Assembler iki biçimden hangisini seçeceğine değere bakarak karar verir. Değer −128…127 aralığındaysa kısa biçim (d8) seçilir ve komut bir bayt kısalır. Değilse uzun biçim (d16) gerekir. [BX+127] üç bayt (8A 47 7F), [BX+128] dört bayttır (8A 87 80 00). 128 sayısı 8 bite sığar ama işaretli olarak −128 diye okunurdu; bu yüzden 16 bitlik biçime geçilir. Değişken adlarının bağıl konumu genellikle 127'den büyük olduğu için dizi[SI] gibi yazımlar hemen her zaman d16 kullanır.

[BX − 2]FEhd8 = −2genişletFFFEhBX = 0100h→ EA = 00FEh0100h + FFFEh = 1 00FEh: 17. bit atılır (16 bit sarma)−128 … +127 arası d8 (1 bayt), dışı d16 (2 bayt)
Şekil 4.1.2: 8 bitlik yer değiştirme, toplamaya katılmadan önce işaretiyle 16 bite genişletilir: FFh, 00FFh değil FFFFh olur ve −1 gibi davranır.

İşlemci 8 bitlik yer değiştirmeyi 16 bitlik yazmaçlarla toplamadan önce işaret genişletme (sign extension) yapar. En yüksek bit 1 ise üst bayt FFh, 0 ise 00h ile doldurulur (Şekil 4.1.2). FC böylece FFFCh olur. FFFCh'yi bir sayıya eklemek, 16 bitlik sınırın dışına taşan elde atıldığında 4 çıkarmakla aynıdır.

Bu son nokta adres hesabının genel bir özelliğidir. Etkin adres her zaman 16 bitle hesaplanır ve sonuç 16 bite sığmazsa taşan bit atılır; adres başa sarar. BX = FFFFh iken [BX+2] erişimi 10001h'ye değil, 0001h'ye gider. 8086, kesimin sonundan taşan bir adresi bir sonraki kesime taşımaz; aynı kesimin başına döndürür.

Örnek 4.1.1

SI = 0010h iken MOV AL, [SI+0FFF8h] komutu hangi bağıl konumdan okur?

Toplama 0010h + FFF8h = 1 0008h verir. Sonucun 17. biti atılır, etkin adres 0008h olur. FFF8h, 16 bitte −8'in ikiye tümleyenidir; komut aslında [SI-8] ile aynı yere gider. Assembler da bunu fark eder ve kısa biçimi seçer: iki yazım da 8A 44 F8 baytlarını üretir. İşlemci F8 baytını işaret genişletmeyle yeniden FFF8h yapar.

4.1.1.5Geçerli ve geçersiz yazımlar

Birleştirme kuralı bir yazımın geçerliliğini hızla sınamaya yarar. Tablo 4.1.3 sunumdaki örnekleri, geçersizlerin nedeniyle birlikte toplar. Geçersiz satırların hepsinde assembler hata verir.

Tablo 4.1.3: Geçerli ve geçersiz bellek işlenenleri.
YazımDurumAçıklama
[BX]geçerliyazmaç dolaylı, DS
[1234h]geçerlidoğrudan adres, DS
[SI+10]geçerliindisli, d8, DS
[BP+DI-2]geçerlitabanlı-indisli, d8, SS
ES:[BX+SI]geçerlikesim önekli, ES
[AX], [CX], [DX]geçersizbu yazmaçlar adres hesabında kullanılamaz
[BL], [BH]geçersiz8 bitlik yazmaç 16 bitlik bağıl konum tutamaz
[BX+BP]geçersiziki taban yazmacı
[SI+DI]geçersiziki indis yazmacı
[SP], [BX*2]geçersiz8086'da yok; 80386 ve sonrasında 32 bitlik adreslemede vardır

Son satır sık karışıklık yaratır. Günümüz x86 işlemcilerinde [ESP+4] ya da [EBX+ESI*4] gibi yazımlar geçerlidir. Bunlar 80386 ile gelen 32 bitlik adreslemenin parçasıdır. 8086'nın 16 bitlik ModR/M tablosunda SP de, ölçekleme çarpanı da yoktur. Yığındaki bir değere ulaşmak için SP önce BP'ye kopyalanır, sonra [BP+n] kullanılır.

Sık yapılan hata

İki yazmacın toplamını adres olarak kullanmak isterken yasak birleşime düşmek. MOV AX, [SI+DI] geçersizdir. İki indis yazmacından biri önce bir taban yazmacına kopyalanırsa iş görülür: MOV BX, SI ardından MOV AX, [BX+DI]. Aynı yol [BX+BP] için de geçerlidir: BP ya da BX'ten biri SI ya da DI'ye aktarılır. Kopyalamada hangi yazmacın seçildiği varsayılan kesimi de değiştirebilir; BP'li bir adres SS'ye gider.

4.1.2Adresleme modu türleri

4.1.2.1İşlenen nerede durur?

Yirmi dört birleşim, işlenenin bellekte bulunduğu durumların hepsini kapsar. Ama bir komutun işleneni bellekte olmak zorunda değildir. Sabit bir sayı doğrudan komutun içine yazılabilir ya da işlenen bir yazmaçta durabilir. Kitaplar adresleme modlarını bu yüzden “işlenen nerede?” sorusuna göre adlandırır. Tablo 4.1.4 sunumdaki sınıflamayı verir.

Tablo 4.1.4: Veri işlenenleri için adresleme modu türleri. Son sütun, BP'siz modlarda varsayılan kesimin DS olduğunu gösterir.
ModÖrnekİşlenen nerede?
Anlık (immediate)MOV AX, 5komutun içinde (sabit)
Yazmaç (register)MOV AX, BXyazmaçta
Doğrudan (direct)MOV AX, [1000h]DS:1000h
Yazmaç dolaylı (register indirect)MOV AX, [BX]DS:BX
Tabanlı (based)MOV AX, [BP+4]SS:BP+4
İndisli (indexed)MOV AL, [SI+3]DS:SI+3
Tabanlı-indisliMOV AL, [BX+DI]DS:BX+DI
Tabanlı-indisli + yer değiştirmeMOV AL, [BX+SI+8]DS:BX+SI+8

Anlık modda işlenen komutun kendisidir. MOV AX, 5 komutunun makine kodu B8 05 00'dır; 5 sayısı komutun son iki baytında durur. İşlemci bu değeri komutu getirirken zaten okumuştur ve belleğe ikinci kez gitmez. Anlık değer yalnız kaynak olabilir. Bir sabitin içine yazı yazılamayacağı için MOV 5, AX anlamsızdır.

Yazmaç modunda işlenen işlemcinin içindedir. MOV AX, BX komutu yürütme biriminin içinde, veri yoluna hiç çıkmadan tamamlanır. Bu yüzden en hızlı moddur; 8086'da 2 saat turu sürer. ModR/M baytında MOD = 11 yazılarak seçilir: MOV AX, BX = 8B C3, yani C3 = 11 000 011 bitleri.

Geri kalan bütün modlar belleğe gider. Bunlarda işlemci önce bir etkin adres (EA, effective address) hesaplar. Etkin adres, işlenenin kesim içindeki konumudur, yani bir bağıl konumdur. Ardından bu bağıl konum kesim yazmacıyla birleştirilir:

fiziksel adres = kesim × 10h + EA

Modların adları etkin adresin nasıl kurulduğunu anlatır. Doğrudan modda EA, komutun içindeki 16 bitlik sabittir. Yazmaç dolaylı modda EA bir yazmacın (BX, BP, SI ya da DI) içeriğidir. Tabanlı modda EA, BX ya da BP ile bir yer değiştirmenin toplamıdır. İndisli modda taban yerine SI ya da DI kullanılır. Tabanlı-indisli modda bir taban ile bir indis toplanır ve buna isteğe bağlı bir yer değiştirme eklenir. Kitaplar arasında adlandırma küçük farklar gösterir. Bazıları [BX+4]'ü “yazmaç göreli”, bazıları “tabanlı” diye anar. Ama hesap her yerde aynıdır.

Tanım 4.1.3

Etkin adres (EA), bir bellek işleneni için köşeli parantezdeki taban yazmacı, indis yazmacı ve yer değiştirmenin 16 bitlik toplamıdır. Toplam FFFFh'yi aşarsa taşan bit atılır. EA kesimin içindeki bağıl konumdur. Fiziksel adres, EA'nın seçilen kesim yazmacının 16 katına eklenmesiyle elde edilen 20 bitlik adrestir.

4.1.2.2Dizgi, G/Ç ve göreceli mod

Üç mod daha vardır. Bunlar köşeli parantezli yazımı kullanmaz. İşlenen ya komutta hiç yazılmaz ya bellekten ayrı bir adres alanında bulunur ya da adres IP'ye göre hesaplanır.

Dizgi modunda işlenenler örtüktür. MOVSB komutu yanında hiçbir işlenen yazılmadan bir baytı DS:SI adresinden ES:DI adresine taşır. Kaynak her zaman DS:SI, hedef her zaman ES:DI'dir. Her işlemden sonra SI ve DI kendiliğinden ilerler. Yön bayrağı DF = 0 ise artar, DF = 1 ise azalır. Bayt işleminde adım 1, sözcük işleminde 2'dir. Dizgi komutlarının ayrıntısı ayrı bir konudur. Burada önemli olan, bu komutlarda adres hesabının yazmaç dolaylı modla aynı yapıda olması ve hedefin DS değil ES kesiminde aranmasıdır.

MOVSB           ; ES:[DI] ← DS:[SI], sonra SI ve DI bir ilerler

G/Ç modunda işlenen bir giriş/çıkış portudur. 8086'nın portları bellekten ayrı, 64 K'lık kendi adres alanındadır. İşlemci bir porta erişirken adres yoluna port numarasını çıkarır ve M/IO̅ hattını 0 yapar. Böylece bellek yongaları değil G/Ç aygıtları yanıt verir. Veri yalnız AL ya da AX üzerinden geçer. Port numarası 0–255 aralığındaysa komutun içine yazılabilir. Daha büyük numaralar DX'e konur.

IN  AL, 45h      ; 45h numaralı porttan bir bayt oku
OUT DX, AX       ; DX'teki porta AX'i yaz

Göreceli modda (relative addressing) komutun içinde hedefin kendisi değil, IP'ye eklenecek işaretli bir uzaklık durur. Atlama komutları bu modu kullanır. Yeni IP, atlama komutundan hemen sonraki komutun adresi ile uzaklığın toplamıdır. Kısa atlamalarda uzaklık 8 bittir ve −128…+127 bayt aralığına ulaşır. Örneğin bir döngünün sonundaki JNZ dongu komutu 75 FA diye kodlanabilir. FA, −6'nın 8 bitlik ikiye tümleyenidir. Komut iki bayt olduğundan atlama, komutun başından 4 bayt geriye gider. Göreceli adreslemenin büyük bir artısı vardır: program bellekte başka bir yere taşınsa da uzaklıklar değişmez.

JNZ dongu       ; 75 FA: IP ← sonraki komutun adresi − 6
Sık yapılan hata

Başka işlemcilerin yazımını 8086'ya taşımak. Komut adları bitişik yazılır: MOVSB doğrudur, MOVS B değildir. OUT komutunda önce port, sonra veri yazmacı gelir: OUT 50h, AL. IN A, 45 yazımı 8085 işlemcisine aittir. 8086'da akümülatörün adı AL ya da AX'tir ve onaltılık sayılar h sonekiyle yazılır.

4.1.2.3Kod izleme: altı adresleme modu

Aşağıdaki küçük COM programı, aynı altı baytlık tablodan farklı modlarla değer okur. Her adımın sonucu izleme tablosunda verilmiştir.

ORG 100h
MOV BX, OFFSET tablo
MOV SI, 2
MOV AH, 7          ; anlık
MOV AL, [tablo+1]  ; doğrudan
MOV CL, [BX]       ; dolaylı
MOV CH, [BX+4]     ; tabanlı
MOV DL, [BX+SI]    ; taban+indis
MOV DH, [BX+SI+3]  ; + d8
RET
tablo DB 11h,22h,33h,44h,55h,66h

ORG 100h satırı assembler'a programın 0100h bağıl konumundan başlayacağını söyler. COM programlarında kod, veri ve yığın aynı 64 KB'lık kesimdedir. emu8086 bu kesimi 0700h paragrafına yükler: CS = DS = ES = SS = 0700h. Komutların uzunlukları toplandığında RET 0115h'ye, tablo 0116h'ye düşer. Tablonun altı baytı 0116h–011Bh bağıl konumlarındadır; fiziksel adresleri 07116h–0711Bh'dir.

MOV BX, OFFSET tablo satırındaki OFFSET işleci, değişkenin içeriğini değil bağıl konumunu verir. Bu değer derleme sırasında bilinir ve komutun içine anlık değer olarak yazılır: BB 16 01. Sonuçta BX = 0116h olur. BX artık tablonun başını gösteren bir işaretçidir. MOV SI, 2 indis yazmacına 2 koyar.

Tablo 4.1.5: Altı adresleme modunun izlemesi (DS = 0700h, BX = 0116h, SI = 0002h; tablo = 11 22 33 44 55 66).
KomutMakine koduModEAFizikselSonuç
MOV AH, 7B4 07anlık——AH = 07h
MOV AL, [tablo+1]A0 17 01doğrudan0117h07117hAL = 22h, AX = 0722h
MOV CL, [BX]8A 0Fyazmaç dolaylı0116h07116hCL = 11h
MOV CH, [BX+4]8A 6F 04tabanlı011Ah0711AhCH = 55h, CX = 5511h
MOV DL, [BX+SI]8A 10tabanlı-indisli0118h07118hDL = 33h
MOV DH, [BX+SI+3]8A 70 03tabanlı-indisli + d8011Bh0711BhDH = 66h, DX = 6633h

Satırlar teker teker okunduğunda her modun farkı açıkça görülür. MOV AH, 7 anlık moddur: 7 sayısı B4 07 komutunun ikinci baytıdır ve belleğe ayrıca gidilmez. MOV AL, [tablo+1] doğrudan moddur. Assembler tablo+1 ifadesini 0116h + 1 = 0117h olarak hesaplar ve bu adresi komuta gömer. Komut, akümülatöre özgü kısa biçimiyle A0 17 01 olur. 0117h'deki bayt tablonun ikinci elemanı olan 22h'dir. AH daha önce 07h yapıldığından AX = 0722h olur.

MOV CL, [BX] yazmaç dolaylı moddur. Adres komutta yazılı değildir; işlemci onu çalışma anında BX'ten alır. EA = 0116h, okunan bayt 11h'dir. MOV CH, [BX+4] tabanlı moddur: EA = 0116h + 4 = 011Ah, okunan değer tablonun beşinci elemanı 55h'dir. CX = 5511h olur. Bu iki komut arasındaki fark, sabit bir uzaklığın eklenmesidir. Bir kaydın alanlarına erişirken BX kaydın başını, yer değiştirme alanın kayıt içindeki yerini tutar.

MOV DL, [BX+SI] tabanlı-indisli moddur: EA = 0116h + 0002h = 0118h, DL = 33h. Son komut buna bir de 8 bitlik yer değiştirme ekler: EA = 0116h + 2 + 3 = 011Bh, DH = 66h. Bu altı erişimin hiçbirinde BP kullanılmadığı için kesim hep DS'dir. Fiziksel adres DS × 10h + EA = 07000h + EA ile bulunur.

tablo (DS:0116h …)11h011622h011733h011844h011955h011A66h011Btaban + indis + d8EA = BX + SI + 3 = 011Bhfiziksel = 07000h + 011Bh = 0711BhAH07hAL22hCL11hCH55hDL33hDH66h
Şekil 4.1.3: Altı adresleme modunun son adımı: MOV DH, [BX+SI+3] etkin adresi 011Bh olan baytı, yani tablonun son elemanını (66h) okur.

Programın son durumu AX = 0722h, BX = 0116h, CX = 5511h, DX = 6633h, SI = 0002h'dir. RET yığından 0000h değerini çeker ve IP = 0000h olur. COM programının yüklendiği kesimin 0000h bağıl konumunda DOS'un yerleştirdiği INT 20h komutu bulunur ve program biter. MOV komutları bayrakları değiştirmediğinden bütün izleme boyunca bayraklar başlangıçtaki gibi kalır: yalnız IF = 1.

4.1.3Etkin adres hesabı

4.1.3.1Adım adım: DS ile

Etkin adres hesabı, yürütme biriminin (EU) içindeki bir toplama ile yapılır. Sonuç, kesim yazmacıyla birleştirilmek üzere veri yolu arabirim birimine (BIU) verilir. BIU'nun kendi toplayıcısı kesimi 4 bit sola kaydırıp EA'yı ekler ve 20 bitlik adresi A19–A0 hatlarına çıkarır. Bu iki aşama bir örnekle izlenebilir:

MOV AL, [BX + SI + 4]   ; DS = 1000h, BX = 0200h, SI = 0030h
  1. Taban yazmacı BX = 0200h alınır.
  2. İndis yazmacı SI = 0030h eklenir: 0230h.
  3. 8 bitlik yer değiştirme +4 eklenir.
  4. EA = 0200h + 0030h + 0004h = 0234h. Toplama 16 bitliktir; burada taşma yoktur.
  5. Adreste BP olmadığından kesim DS'dir. Fiziksel adres = 1000h × 10h + 0234h = 10000h + 0234h = 10234h. AL, bu adresteki baytı alır.
BX0200+ SI0030+ d80004EA0234Fiziksel adresDS × 10h = 10000h+ EA = 0234h10234hAL ← [10234h]
Şekil 4.1.4: MOV AL, [BX + SI + 4] için etkin adres ve fiziksel adres: BX + SI + 4 = 0234h; DS = 1000h ile 10234h.

Kesimi 10h ile çarpmak, onaltılık yazımda sağa bir sıfır eklemek demektir: 1000h → 10000h. İkili düzeyde bu, 16 bitlik sayıyı 4 bit sola kaydırıp en düşük dört bite 0 koymaktır. Fiziksel adres bu yüzden kolay hesaplanır: kesimin sonuna bir 0 yazılır, altına EA sağa yaslanarak yazılır ve iki sayı toplanır.

4.1.3.2Adım adım: BP ile

Adreste BP bulunursa aynı hesap SS kesimiyle yapılır. Sunumdaki ikinci örnek bir sözcük okur ve negatif bir yer değiştirme kullanır:

MOV AX, [BP + DI - 2]   ; SS = 2000h, BP = 0100h, DI = 0010h
  1. Taban yazmacı BP = 0100h alınır.
  2. İndis yazmacı DI = 0010h eklenir: 0110h.
  3. Yer değiştirme −2'dir; makine kodunda FE baytı olarak durur ve işaret genişletmeyle FFFEh olur.
  4. EA = 0100h + 0010h + FFFEh = 1 010Eh → 010Eh. Taşan bit atılır; sonuç 0110h − 2 ile aynıdır.
  5. BP kullanıldığı için kesim SS'dir: 20000h + 010Eh = 2010Eh. AX bir sözcük olduğundan iki bayt okunur: AL ← [2010Eh], AH ← [2010Fh].
BP0100+ DI0010+ d8FFFEEA010EFiziksel adresSS × 10h = 20000h+ EA = 010Eh2010EhAX ← [2010Eh], [2010Fh]
Şekil 4.1.5: MOV AX, [BP + DI - 2]: EA = 010Eh; BP kullanıldığı için kesim SS ve fiziksel adres 2010Eh. Sözcüğün ikinci baytı 2010Fh'dedir.

Bu komutun makine kodu 8B 43 FE'dir. ModR/M baytı 43 = 01 000 011: MOD = 01 (d8 var), REG = 000 (AX), R/M = 011 ([BP+DI]). Komutun hiçbir yerinde “SS” yazmaz. Kesim seçimi R/M alanının kendisinden gelir: R/M değeri BP içeren bir birleşimse donanım SS'yi, değilse DS'yi seçer.

Sözcük okumanın veri yolu açısından bir ayrıntısı vardır. 8086'nın veri yolu 16 bittir, ama bellek bayt bayt adreslenir. Çift adresteki bir sözcüğün iki baytı tek bir yol döngüsünde birlikte gelir. Bu örnekteki 2010Eh çift olduğundan okuma tek döngüdür. Sözcük tek bir adreste başlasaydı, örneğin 2010Fh'de, işlemci önce düşük baytı yolun yüksek yarısından, sonra yüksek baytı ayrı bir döngüde yolun düşük yarısından okurdu. Sonuç aynı olur ama erişim bir yol döngüsü, yani en az 4 saat turu uzar. Bu yüzden assembler'larda sözcük değişkenlerini çift adrese hizalayan EVEN yönergesi vardır.

4.1.3.3Etkin adres hesaplayıcısı

Sunumdaki hesaplayıcı ve Adresleme Modları simülatörü aynı hesabı etkileşimli olarak yapar. Taban sütunundan BX, BP ya da hiçbiri; indis sütunundan SI, DI ya da hiçbiri seçilir ve bir yer değiştirme girilir. Yazmaç ve kesim değerleri onaltılık, yer değiştirme onluk (−2) ya da onaltılık (1Ah) yazılabilir. Araç geçerli bir birleşim için EA'yı, varsayılan kesimi ve fiziksel adresi verir. Elle yapılan hesabın denetimi için uygundur. Aynı hesap kâğıt üzerinde üç kurala dayanır: toplamayı 16 bitte yapmak, BP varsa SS'yi seçmek ve kesimi 10h ile çarpmak.

Örnek 4.1.2

DS = 3000h, SS = 4000h, BX = 0010h, BP = FFFEh, SI = 0005h. [BX+SI+20h] ve [BP+4] işlenenlerinin etkin ve fiziksel adresleri nedir?

Birinci işlenende BP yoktur. EA = 0010h + 0005h + 0020h = 0035h, kesim DS: 30000h + 0035h = 30035h.

İkinci işlenende EA = FFFEh + 0004h = 1 0002h'dir. 17. bit atılır ve EA = 0002h olur. BP olduğundan kesim SS: 40000h + 0002h = 40002h. Sarma olmasaydı adres 50002h çıkardı. Bu değer SS kesiminin dışındadır ve 8086 böyle bir adres üretmez.

4.1.3.4Veri yapısına göre mod seçimi

Aynı bayta birden çok modla ulaşılabilir. Doğru modu seçmek için verinin hangi parçasının derleme sırasında sabit, hangisinin çalışma sırasında değişken olduğuna bakılır. Sabit parça yer değiştirmeye, değişken parçalar yazmaçlara konur. Tablo 4.1.6 yaygın durumları özetler.

Tablo 4.1.6: Erişilen veriye göre uygun adresleme modu.
Erişilen veriUygun modÖrnek
Tek bir değişkendoğrudanMOV AX, sayac
İşaretçinin gösterdiği elemanyazmaç dolaylıMOV AL, [SI]
Dizinin i. elemanı (dizi sabit, indis değişken)indisli + d16MOV AL, dizi[SI]
Bir kaydın (yapının) alanıtabanlı + d8MOV AX, [BX+2]
Matris ya da kayıt dizisitaban + indis + dMOV AL, mat[BX+SI]
Yığındaki parametre ya da yerel değişkentabanlı, BP ile (SS)MOV AX, [BP+4]
Başka kesimdeki tamponkesim önekliMOV AL, ES:[DI]

Tablonun arkasındaki düşünce şudur. Taban yazmacı hangi kaydın ya da hangi satırın işlendiğini gösterir. Kayıt değiştiğinde yalnız taban yazmacı güncellenir. İndis yazmacı kaydın içindeki elemanı sayar ve döngüde artırılır. Yer değiştirme dizinin ya da alanın sabit konumudur; assembler onu komuta gömer. Örneğin her biri 6 baytlık öğrenci kayıtlarından oluşan bir dizide, kaydın 4. baytındaki not alanı [BX+4] ile okunur. Sonraki kayda geçmek için ADD BX, 6 yeterlidir; okuma komutu aynı kalır.

Yığın satırı ayrı bir öneme sahiptir. Bir alt programa yığın üzerinden parametre geçirildiğinde, alt program SP'yi BP'ye kopyalar ve parametrelere [BP+4], [BP+6] gibi sabit uzaklıklarla ulaşır. BP'nin varsayılan kesiminin SS olması bu kullanım için seçilmiştir: yığın SS kesimindedir.

4.1.3.5Kod izleme: matris elemanına erişim

Taban + indis + yer değiştirme modunun en açık kullanımı iki boyutlu bir dizidir. Aşağıdaki programda mat, 3 satır ve 4 sütundan oluşan bir bayt matrisidir. Eleman değerleri bir bakışta tanınsın diye seçilmiştir: onaltılık değerin ilk basamağı satırın, ikinci basamağı sütunun 1'den başlayan sırasıdır. Örneğin 32h üçüncü satırın ikinci elemanıdır. Program satır ve sütunları 0'dan saydığı için bu eleman mat[2][1] diye anılır.

org 100h
mov bx, 2*4          ; satır 2
mov si, 1            ; sütun 1
mov al, mat[bx+si]   ; mat[2][1]
mov si, 3            ; sütun 3
mov ah, mat[bx+si]   ; mat[2][3]
sub bx, 4            ; satır 1
mov dl, mat[bx+si]   ; mat[1][3]
ret
mat db 11h,12h,13h,14h
    db 21h,22h,23h,24h
    db 31h,32h,33h,34h

Matris bellekte satır öncelikli düzende (row-major order) saklanır: önce 0. satırın dört baytı, ardından 1. satırın, en son 2. satırın baytları gelir. mat 0119h'de başlar ve 0124h'de biter. Bir elemanın adresi şu formülle bulunur:

adres(mat[satır][sütun]) = mat + satır × sütun sayısı + sütun

Programda satır × sütun sayısı terimi BX'e, sütun terimi SI'ya, mat'ın bağıl konumu yer değiştirmeye konmuştur. mat[bx+si] yazımı [bx+si+0119h] ile aynıdır ve 8A 80 19 01 diye kodlanır. 0119h, 127'den büyük olduğu için d16 kullanılır.

Tablo 4.1.7: Matris erişiminin izlemesi (mat = 0119h, satır uzunluğu 4 bayt).
AdımKomutBXSIEAAXDL
1mov bx, 2*40008h0000h—0000h00h
2mov si, 10008h0001h—0000h00h
3mov al, mat[bx+si]0008h0001h0122h0032h00h
4mov si, 30008h0003h—0032h00h
5mov ah, mat[bx+si]0008h0003h0124h3432h00h
6sub bx, 40004h0003h—3432h00h
7mov dl, mat[bx+si]0004h0003h0120h3432h24h

Adım 1'de BX = 2 × 4 = 8 olur. Çarpmayı assembler derleme sırasında yapar ve komutun içine 0008h yazar. 2. satır matrisin başından 8 bayt ileridedir. Adım 2'de SI = 1 sütunu seçer. Adım 3'te EA = 0119h + 8 + 1 = 0122h olur ve AL = 32h okunur. Bu, matrisin 2. satırının 1. sütunudur (ikisi de 0'dan sayılarak).

Adım 4 ve 5 aynı satırda kalıp sütunu değiştirir. BX dokunulmadan kaldığı için satır sabittir. EA = 0119h + 8 + 3 = 0124h ve AH = 34h olur; AX = 3432h. Okuma komutu öncekinin aynısıdır, yalnız indis yazmacının değeri değişmiştir. Adım 6'daki sub bx, 4 bir satır yukarı çıkar: BX = 0004h. SI = 3 korunduğu için sütun aynı kalır. Adım 7'de EA = 0119h + 4 + 3 = 0120h, DL = 24h olur. Bu, 1. satırın 3. sütunudur.

mat (satır başına 4 bayt)sütun 0123satır 0 · 011911121314satır 1 · 011D21222324satır 2 · 012131323334BX0008SI0001AH00AL32DL00EA = 0119 + 0008 + 0001= 0122h
Şekil 4.1.6: Matris erişiminin 3. adımı: BX satırı (8 bayt ileri), SI sütunu (1) seçer; EA = 0122h ve AL = 32h.

sub bx, 4 MOV'dan farklı olarak bayrakları değiştirir. 8 − 4 = 4 sonucu sıfır değildir ve elde gerekmez; ZF = 0, CF = 0, SF = 0 olur. 4 = 0000 0100b'de tek sayıda 1 bulunduğundan eşlik bayrağı PF = 0'dır. Program sonunda AX = 3432h, BX = 0004h, DL = 24h'dir. Üç farklı eleman tek bir adresleme kalıbıyla okunmuştur.

Sözcüklerden oluşan bir matriste formüldeki iki terim de 2 ile çarpılır: adres = mat + (satır × sütun sayısı + sütun) × 2. Bir sözcük 2 bayt yer kaplar ve indis yazmaçları her zaman bayt sayar.

4.1.3.6Etkin adres hesap süresi

8086'da etkin adres, EU içinde ayrı bir toplama ile hesaplanır. 80286 ve sonraki işlemcilerde bu iş için ayrı bir adres birimi vardır. 8086'da ise EA hesabının süresi komutun kendi süresine eklenir ve moda göre değişir. Tablo 4.1.8, Intel 8086 kullanıcı kılavuzundaki EA süre tablosunu verir.

Tablo 4.1.8: 8086'da etkin adres hesabının süresi (saat turu).
Etkin adres birleşimiSaat turu
[BX], [BP], [SI], [DI]5
doğrudan [d16]6
[BP+DI], [BX+SI]7
[BP+SI], [BX+DI]8
tek yazmaç + d8/d169
[BP+DI+d], [BX+SI+d]11
[BP+SI+d], [BX+DI+d]12
kesim öneki+2

Bellekten yazmaca taşıyan genel MOV komutu 8 tur artı EA süresi tutar. Yazmaçtan yazmaca MOV 2 turdur. Buna göre:

  • MOV AX, BX: 2 tur. Belleğe gidilmez.
  • MOV CL, [BX]: 8 + 5 = 13 tur.
  • MOV CL, [BX+DI+4]: 8 + 12 = 20 tur.
  • MOV CL, ES:[BX]: 8 + 5 + 2 = 15 tur.

Tablodaki tuhaf bir ayrıntı dikkat çeker: [BX+SI] 7, [BX+DI] 8 turdur. Bu fark 8086'nın iç düzeninden gelir ve programcı için küçük bir seçim ölçütü olabilir. Tek adreste başlayan bir sözcük ise ikinci bir yol döngüsü gerektirdiğinden aktarım başına 4 tur daha ekler. 5 MHz'lik bir 8086'da bir saat turu 200 ns'dir. MOV CL, [BX+DI+4] böylece 20 × 200 ns = 4 µs sürer; aynı iş yazmaçtan yazmaca 0,4 µs'dir.

Bu farklar, sık okunan bir değeri döngü boyunca bir yazmaçta tutmanın neden hızlı olduğunu açıklar. Döngünün her turunda belleğe gidilmez ve EA hesabı tamamen ortadan kalkar. AL ve AX'e özgü doğrudan adresli kısa biçim (A0/A1) de ayrıca hızlıdır: EA hesabı içermez ve 10 tur sürer. MOV CL, [1234h] ise 8 + 6 = 14 turdur.

4.1.4Kesim ve bağıl konum

4.1.4.1Kesim:bağıl konumdan fiziksel adrese

8086'nın adres yolu 20 hattan oluşur: A19–A0. 20 bitle 220 = 1 048 576 farklı bayt, yani 1 MB adreslenebilir. İşlemcinin yazmaçları ise 16 bittir ve tek bir yazmaç ancak 64 KB'lık bir alanı tarayabilir. Tasarımcılar bu uyumsuzluğu iki 16 bitlik sayıyı birleştirerek çözmüştür. Birinci sayı belleğin hangi bloğunun kullanıldığını, ikinci sayı o bloğun içindeki konumu söyler.

Tanım 4.1.4

Bir kesim yazmacındaki (CS, DS, SS, ES) değere kesim (segment) denir. Etkin adres hesabından ya da IP, SP gibi bir yazmaçtan gelen adrese bağıl konum (offset) denir. Bir adres kesim:bağıl konum biçiminde yazılır. Fiziksel adres

fiziksel adres = kesim × 10h + bağıl konum

ile bulunur. Kesim belleğin 16 baytlık bir sınırda başlayan bloğunu, bağıl konum o bloğun içindeki baytı gösterir.

Sunumdaki örnekte DS = 1234h ve SI = 7890h'dir. Adres 1234:7890 diye yazılır. Hesap dört adımda yapılır (Şekil 4.1.7):

  1. Kesim ve bağıl konum alınır: 1234h ve 7890h.
  2. Kesim 10h ile çarpılır, yani 4 bit sola kaydırılır: 12340h. Onaltılık yazımda bu, sağa bir 0 eklemektir.
  3. Bağıl konum, toplamaya girmek üzere sağa yaslanır: 07890h.
  4. İki sayı toplanır: 12340h + 07890h = 19BD0h.
DS1234× 10h12340+ SI7890=19BD0elde: 4 + 9 = D, 3 + 8 = B,2 + 7 = 9, 1 + 0 = 1 → 19BD0h
Şekil 4.1.7: 1234:7890 adresinin fiziksel karşılığı: kesim 4 bit sola kaydırılır (12340h), bağıl konum (7890h) eklenir; sonuç 19BD0h.

Toplama basamak basamak yapıldığında 0 + 0 = 0, 4 + 9 = 13 = Dh, 3 + 8 = 11 = Bh, 2 + 7 = 9, 1 + 0 = 1 bulunur. Hiçbir basamakta elde oluşmadığından sonuç kolayca okunur. Elde oluşan bir örnek 1A5D:FFF3 çiftidir. 1A5D0h + 0FFF3h hesabında sağdan başlanır: 0 + 3 = 3; D + F = 13 + 15 = 28 = 1Ch, basamağa C yazılır ve 1 elde aktarılır; 5 + F + 1 = 21 = 15h, basamağa 5; A + F + 1 = 26 = 1Ah, basamağa A; 1 + 0 + 1 = 2. Sonuç 2A5C3h'dir. Onaltılık toplamada bir basamak 15'i aşarsa 16 çıkarılır ve bir sonraki basamağa 1 elde aktarılır.

Bu toplama donanımda BIU'nun içindeki ayrı bir 20 bitlik toplayıcıyla yapılır. Kesim yazmacının 16 biti toplayıcının yüksek 16 girişine, en düşük 4 girişe 0 bağlanarak verilir. Bu bağlantı “10h ile çarpma” işinin bütün devresidir; ayrı bir çarpıcı yoktur. Toplayıcının çıkışı adres mandallarına ve oradan A19–A0 hatlarına gider. Komut getirirken BIU aynı toplayıcıyı CS ve IP ile kullanır.

Kesimin 16 ile çarpılmasının bir sonucu, kesimlerin yalnız 16'nın katı olan adreslerde başlayabilmesidir. Bu 16 baytlık birime paragraf denir. Kesim yazmacındaki sayı, kesimin kaçıncı paragrafta başladığını söyler. Bir kesimin bağıl konumu 16 bit olduğundan kesim en çok 216 = 64 KB uzunluğundadır. Ardışık iki kesim değeri yalnız 16 bayt aralıklı başladığından kesimler birbirinin üstüne biner. Aynı fiziksel bayta pek çok farklı kesim:bağıl konum çiftiyle ulaşılabilir. Örneğin 0700:0100, 0710:0000 ve 06F0:0200 çiftlerinin üçü de 07100h adresini gösterir.

Toplam 20 bitten taşarsa ne olur? FFFF:0010 çiftinin toplamı FFFF0h + 0010h = 100000h'dir; 21 bit gerekir. 8086'da 21. hat yoktur ve taşan bit atılır. Adres 00000h'ye, belleğin başına sarar. FFFF:0010 ile FFFF:FFFF arasındaki adresler böylece 00000h–0FFEFh bölgesine düşer.

4.1.4.2Adres hatları ve bellek kapasitesi

Adres hattı sayısı ile bellek büyüklüğü arasındaki ilişki sayısal tasarımdaki kod çözücülerden tanıdıktır. n adres hattı 2n farklı ikili örüntü üretir ve her örüntü bir bellek konumunu seçer. Bir konumda kaç bit bulunduğunu ise veri hattı sayısı belirler:

kapasite = 2n × veri genişliği

8086'nın 20 adres hattı 220 = 1 048 576 konum seçer. Her konum bir bayt olduğundan kapasite 1 MB'tır ve adresler 00000h ile FFFFFh arasındadır. Bir kesimin sınırı ise bağıl konumdan gelir: 16 bit → 216 = 65 536 bayt = 64 KB. Tablo 4.1.9 farklı hat sayıları için kapasiteyi verir.

Tablo 4.1.9: Adres ve veri hattı sayısına göre bellek kapasitesi.
Adres / veri hattıKonum sayısıKapasite
12 / 8212 = 40964096 × 1 B = 4 KB
16 / 4216 = 64 K64 K × 4 bit = 256 Kbit = 32 KB
16 / 864 K64 KB (bir kesim)
20 / 81 M1 MB (8086)
24 / 1616 M16 M × 2 B = 32 MB
32 / 84 G4 GB (80386)

Bir bellek yongasında veri hattı sayısı, yonganın sözcük genişliğidir. Kapasite bayt cinsinden istenirse toplam bit sayısı 8'e bölünür. 16 adres ve 4 veri hattı olan bir yonga 65 536 × 4 = 262 144 bit, yani 32 768 bayt tutar. 8086 sisteminde bu tür yongalar yan yana bağlanarak 8 ya da 16 bitlik bir veri yolu kurulur.

Soru tersine de sorulabilir: belirli bir kapasite için en az kaç adres hattı gerekir? Bunun için kapasiteye eşit ya da ondan büyük ilk 2'nin kuvveti bulunur. Bellek bayt adresli ise 6 GB için 232 = 4 GB yetmez; 233 = 8 GB yeter ve 33 hat gerekir. 4 KB için 212 = 4096 tam olarak yeter; 12 hat gerekir (A0–A11).

Sık yapılan hata

Bit ile baytı karıştırmak. 20 adres ve 16 veri hattı olan bir yonga 220 × 16 bit = 16 Mbit tutar. Bu 2 MB'tır, 16 MB değildir. Kapasite yazılırken birimin bit mi bayt mı olduğu açıkça belirtilmelidir. 8086 belleği bayt adreslidir; orada 20 hat 1 MB demektir.

4.1.4.3Ters hesap: fiziksel adresten kesim:bağıl konuma

Fiziksel adres verilip kesim ve bağıl konum istendiğinde tek bir cevap yoktur. Kesimler üst üste bindiği için pek çok çift aynı adresi verir. Doğru soru, kesim yazmacının alabileceği değerlerin aralığıdır. Sunumdaki örnekte 2A5C3h adresine DS:SI ile erişilmek isteniyor.

En büyük DS. SI'nın en küçük olduğu durumdur. DS × 10h'nin 2A5C3h'yi aşmaması gerekir. Adresin ilk dört onaltılık basamağı alınırsa DS = 2A5Ch olur. DS × 10h = 2A5C0h ve SI = 2A5C3h − 2A5C0h = 0003h kalır. DS 2A5Dh olsaydı 2A5D0h zaten 2A5C3h'den büyük olurdu.

En küçük DS. SI'nın en büyük olduğu durumdur. SI en çok FFFFh olabilir. Bu durumda DS × 10h ≥ 2A5C3h − FFFFh = 1A5C4h olmalıdır. 1A5C4h'yi 10h'ye bölmek 1A5C,4h verir. DS tamsayı olduğu için yukarı yuvarlanır: DS = 1A5Dh. O zaman SI = 2A5C3h − 1A5D0h = FFF3h olur.

Kaç çift? DS her bir arttığında kesimin başı 10h ileri gider ve aynı adres için SI 10h azalır. DS, 1A5Dh ile 2A5Ch arasındaki her değeri alabilir. Çift sayısı 2A5Ch − 1A5Dh + 1 = 0FFFh + 1 = 1000h = 4096'dır.

4096 geçerli DS değeriDS = 1A5DhDS = 2A5ChSI = FFF3hSI = 0003hsol: SI > FFFFh olurdusağ: SI < 0 olurdu
Şekil 4.1.8: 2A5C3h adresi için DS'nin alabileceği değerler: en küçük 1A5Dh (SI = FFF3h), en büyük 2A5Ch (SI = 0003h); aralıkta 4096 çift vardır.

Böyle bir hesabın denetimi her zaman ileri yönde yapılır. 1A5Dh × 10h + FFF3h = 1A5D0h + FFF3h = 2A5C3h. 2A5Ch × 10h + 0003h = 2A5C0h + 3 = 2A5C3h. İki uç da aynı fiziksel adresi verir.

Aralığın uzunluğu her adres için aynı değildir. Çok küçük adreslerde DS'nin alt sınırı 0'a dayanır. Örneğin 00345h adresi için DS en küçük 0000h, en büyük 0034h'dir ve yalnız 35h = 53 çift vardır. 0FFF0h ve üstündeki adreslerde aralık her zaman 4096 çifttir. Bu sayımda 1 MB sınırındaki başa sarma hesaba katılmamıştır; FFFF:0355 gibi sarmalı çiftler de 00345h'ye gider.

4.1.4.4Kesim öneki

Varsayılan kesim kuralı çoğu durumda doğru kesimi seçer. Bazen ise program, veri kesiminin dışındaki bir bayta ulaşmak ister. Bunun için köşeli parantezin önüne bir kesim yazmacının adı ve iki nokta yazılır. Bu yazıma kesim öneki (segment override prefix) denir.

MOV AX, 0B800h
MOV ES, AX          ; ES = video belleği
MOV BX, 0
MOV AL, ES:[BX]     ; ES:0000'dan oku
MOV AL, [BX]        ; DS:0000'dan oku
MOV DL, SS:[SI]     ; SS:SI'dan oku

Önek makine kodunda komutun önüne eklenen bir baytlık bir koddur: ES: = 26h, CS: = 2Eh, SS: = 36h, DS: = 3Eh. İşlemci bu baytı okuyunca yalnız arkasından gelen komut için varsayılan kesimi değiştirir. Önek bir sonraki komuta taşınmaz. MOV AL, ES:[BX] böylece 26 8A 07 olur. Öneksiz MOV AL, [BX] komutunun 8A 07 kodunun önüne 26 eklenmiştir. EA hesabına da 2 saat turu eklenir.

Önek üç durumda gerekir:

  • DS'yi değiştirmeden başka bir kesimdeki veriye erişmek. Video belleği en sık örnektir.
  • Yığındaki bir veriye BP dışındaki bir yazmaçla erişmek: SS:[BX].
  • Kod kesimindeki bir tabloya erişmek: CS:[SI]. Bazı programlar sabit tabloları kodun yanına koyar; DS başka bir yeri gösterse de tablo CS ile okunur.

Her önek her erişimi değiştiremez. IP her zaman CS ile, SP her zaman SS ile kullanılır; bu eşleşmeler donanıma bağlıdır. Komut getirme işlemi CS:IP'den, yığın işlemleri (PUSH, POP, CALL, RET) SS:SP'den yapılır. Dizgi komutlarının hedefi olan ES:DI de değiştirilemez. Dizgi kaynağı DS:SI ise önekle başka bir kesime yönlendirilebilir.

Tanım 4.1.5

Varsayılan kesim (default segment), bir bellek erişiminde önek yoksa kullanılan kesimdir. Komut getirme için CS (IP ile), yığın işlemleri için SS (SP ile), BP içeren adresler için SS, dizgi hedefi için ES (DI ile), diğer bütün veri erişimleri için DS'dir. Kesim öneki, veri erişimlerinin varsayılan kesimini yalnız o komut için değiştirir.

4.1.4.5Kod izleme: ES ile video belleği

IBM PC uyumlu bilgisayarlarda renkli metin ekranının içeriği B8000h fiziksel adresinden başlayan bellekte durur. Ekran kartı bu belleğe yazılan her baytı hemen ekrana yansıtır. Ekranın her karakter hücresi iki bayttır: önce karakterin ASCII kodu, sonra rengi belirleyen öznitelik baytı. Bir satır 80 hücre, yani 160 bayttır. Aşağıdaki program ES ile ekranın 1. satırının ilk hücresine sarı bir K yazar ve aynı bağıl konumu bir de DS ile okur.

ORG 100h
MOV AX, 0B800h
MOV ES, AX         ; ES = video
MOV BX, 00A0h      ; satır 1
MOV BYTE PTR ES:[BX], 'K'
MOV BYTE PTR ES:[BX+1], 1Eh
MOV AL, [BX]       ; DS:00A0h
MOV DL, ES:[BX]    ; B800:00A0h
RET
Tablo 4.1.10: Kesim öneki programının izlemesi (DS = 0700h; video hücresi başlangıçta 20h 07h).
IPKomutMakine koduErişilen adresSonuç
0100hMOV AX, 0B800hB8 00 B8—AX = B800h
0103hMOV ES, AX8E C0—ES = B800h, DS = 0700h
0105hMOV BX, 00A0hBB A0 00—BX = 00A0h
0108hMOV BYTE PTR ES:[BX], 'K'26 C6 07 4BB80A0h[B80A0h] = 4Bh
010ChMOV BYTE PTR ES:[BX+1], 1Eh26 C6 47 01 1EB80A1h[B80A1h] = 1Eh
0111hMOV AL, [BX]8A 07070A0hAL = 00h
0113hMOV DL, ES:[BX]26 8A 17B80A0hDL = 4Bh
0116hRETC3yığınIP = 0000h

İlk iki komut ES'yi kurar. 8086'da bir kesim yazmacına sabit doğrudan yüklenemez; B800h önce AX'e, oradan ES'ye aktarılır. DS hâlâ programın kendi kesimini (0700h) gösterir. Bu sayede programın değişkenlerine erişim bozulmaz. Üçüncü komut BX'e 00A0h = 160 koyar. Bu sayı (1 × 80 + 0) × 2 hesabından gelir ve 1. satırın ilk hücresinin video belleğindeki bağıl konumudur (satırlar 0'dan sayılır).

Dördüncü komut ES: önekiyle başlar. Makine kodundaki 26 baytı, arkasından gelen C6 07 4B (“BX'in gösterdiği baytı 4Bh yap”) komutunun ES kesimine gitmesini sağlar. Fiziksel adres B8000h + 00A0h = B80A0h'dir ve buraya 'K' harfinin ASCII kodu 4Bh yazılır. Beşinci komut bir sonraki bayta 1Eh yazar. 1Eh = 0001 1110b öznitelik baytıdır: zemin rengi bitleri (6–4) 001 = mavi, yazı rengi bitleri (3–0) 1110 = sarı. Ekranda mavi zemin üzerinde sarı bir K belirir.

Altıncı komut önek taşımaz. [BX] varsayılan olarak DS'yi kullanır ve 07000h + 00A0h = 070A0h adresini okur. Bu adres COM programının önündeki 256 baytlık PSP (program kesimi öneki) alanına düşer; örnekte orada 00h vardır ve AL = 00h olur. Aynı bağıl konum farklı bir kesimle bambaşka bir bayta gitmiştir. Yedinci komut yeniden ES: önekini kullanır ve video belleğine yazılan 4Bh'yi okur: DL = 4Bh.

DS = 0700h07000h + 00A0h = 070A0h00h+0ES = B800hB8000h + 00A0h = B80A0h4Bh+01Eh+1ekran, satır 1:KAL00hDL00h
Şekil 4.1.9: Aynı bağıl konum (00A0h) iki kesimde: önek yokken DS ile 070A0h okunur (AL = 00h); ES: önekiyle B80A0h'deki 'K' (4Bh) okunur.

Programın sonunda ES = B800h, DS = 0700h'dir. Önek yalnız yazıldığı komutu etkilemiş, DS'ye hiç dokunmamıştır.

4.1.4.6Kod izleme: BP ve SS tuzağı

COM programlarında CS, DS, SS ve ES aynı değeri taşır. Bu yüzden bir COM programında yanlış kesimin seçilmesi çoğu zaman fark edilmez. Kesimleri ayrı olan bir EXE programında ise BP ile veriye erişmek yanlış bayt getirir. Aşağıdaki program bu tuzağı gösterir.

veri segment
bos db 3 dup(0)
x db 'D'
veri ends
yigin segment stack
dw 64 dup(0)
yigin ends
kod segment
assume cs:kod, ds:veri, ss:yigin
basla:
mov ax, veri
mov ds, ax
mov bp, offset x
mov al, [bp]         ; SS:BP okunur!
mov bl, ds:[bp]      ; DS:BP
mov si, offset x
mov cl, [si]         ; DS:SI
mov ax, 4C00h
int 21h
kod ends
end basla

Programda üç kesim tanımlanmıştır. veri kesimi dört bayttır: üç sıfır baytı ve 'D' harfini taşıyan x. x'in bağıl konumu 0003h'dir. yigin kesimi 64 sözcüklük, sıfırla dolu bir yığındır. stack sözcüğü bağlayıcıya bunun programın yığını olduğunu söyler. Yükleyici programı açarken SS'yi bu kesime, SP'yi onun sonuna (0080h) kurar. assume yönergesi kod üretmez; assembler'a hangi kesim yazmacının hangi kesimi göstereceğini bildirir.

Programın yükleme yerleşimi şöyledir. DOS, PSP'yi 0700h paragrafına koyar; programın görüntüsü 256 bayt ileride, 0710h'de başlar. Kesimler paragraf sınırlarına hizalanarak tanım sırasıyla dizilir. Dört baytlık veri bir paragraf tutar: 0710h. yigin hemen arkasında 0711h'de, kod ise 128 baytlık yığından sonra 0719h'de başlar. Bu değerler örnek bir yerleşimdir. Gerçek bir DOS'ta paragraf numaraları belleğin dolu kısmına göre değişir; hesabın mantığı aynı kalır.

Tablo 4.1.11: BP ile veriye erişimin izlemesi (veri = 0710h, yigin = 0711h; x = 0710:0003 = 07103h).
KomutMakine koduDSSSErişilen adresSonuç
mov ax, veriB8 10 070700h0711h—AX = 0710h
mov ds, ax8E D80710h0711h—DS = 0710h
mov bp, offset xBD 03 000710h0711h—BP = 0003h
mov al, [bp]8A 46 000710h0711hSS:0003 = 07113hAL = 00h
mov bl, ds:[bp]3E 8A 5E 000710h0711hDS:0003 = 07103hBL = 44h ('D')
mov si, offset xBE 03 000710h0711h—SI = 0003h
mov cl, [si]8A 0C0710h0711hDS:0003 = 07103hCL = 44h ('D')
mov ax, 4C00h / int 21hB8 00 4C / CD 210710h0711h—DOS'a dönüş, kod 0

Program başladığında DS veri kesimini göstermez; yükleyici DS'yi PSP'ye (0700h) kurar. mov ax, veri komutu veri kesiminin paragraf numarasını AX'e yükler. Bu sayı yükleme anında belli olur; yükleyici EXE dosyasındaki yeniden yerleştirme tablosuna (relocation table) bakarak komutun içine yazar. mov ds, ax ardından DS = 0710h olur. SS = 0711h ayrı bir bloktur; bu programda DS ≠ SS'dir.

mov bp, offset x BP'ye x'in doğru bağıl konumunu (0003h) koyar. Adres doğrudur; sorun kesimdedir. mov al, [bp] komutunda önek yoktur ve adreste BP vardır. İşlemci SS'yi seçer ve 0711h × 10h + 3 = 07113h adresini okur. Orası yığının dördüncü baytıdır ve içinde 00h vardır. AL = 00h olur; 'D' gelmemiştir. Assembler hiçbir hata vermez, çünkü komut geçerlidir.

mov bl, ds:[bp] komutunda DS: öneki varsayılanı değiştirir. Makine kodunun başına 3E baytı eklenir ve 07103h okunur: BL = 44h ('D'). Aynı bağıl konum SI'ya alındığında önek gerekmez. [si] varsayılan olarak DS kullanır ve CL = 44h olur. Son iki komut DOS'un 4Ch hizmetini çağırır: AH = 4Ch “programı bitir”, AL = 0 dönüş kodudur.

veri: DS = 0710h000000000001000002440003fiz. 07100h…yığın: SS = 0711h000000000001000002000003fiz. 07110h…BP0003SI0000AL00BL00CL00SS:0003 → 07113h
Şekil 4.1.10: mov al, [bp] adımı: BP = 0003h doğru bağıl konumdur, ama varsayılan kesim SS olduğu için yığının 07113h baytı okunur (AL = 00h). 'D' harfi veri kesiminde 07103h'dedir.

Bu izlemeden çıkan kural basittir. Veriye erişmek için BX, SI ya da DI; yığına erişmek için BP seçilir. BP ile veri kesimine erişmek gerçekten gerekiyorsa DS: öneki yazılır. mov al, [bp] komutunun makine kodundaki 46 00 ayrıntısı da dikkat çeker. Yer değiştirmesiz [BP] kodlanamadığı için assembler [BP+0] üretmiştir.

Sık yapılan hata

Bir değişkene BP ile erişip COM programında doğru sonuç aldıktan sonra kodu EXE programına taşımak. COM programında CS = DS = SS olduğundan [BP] ile DS:[BP] aynı bayta gider ve hata görünmez. Kesimleri ayrı bir EXE programında aynı kod yığından okur. Hata derleme sırasında değil, yanlış değerler ortaya çıktığında fark edilir.

4.1.4.7Kesim yazmacını değiştirmek

Kesim yazmaçlarının değeri değiştirilebilir, ama her birinin kendine özgü kuralları vardır.

PUSH DS            ; DS'yi sakla
MOV  AX, 0B800h
MOV  DS, AX        ; geçici kesim
MOV  BYTE PTR [0], 'Z'
POP  DS            ; değişkenler geri
MOV  AX, yeni_yigin
MOV  SS, AX        ; ardından hemen
MOV  SP, 0400h     ; SP kurulur

DS. Assembly'deki değişken adları yalnız bağıl konumdur. Program DS'yi değiştirirse aynı ad başka kesimdeki bir bayta gider. Kodun ilk dört satırı ekranın sol üst köşesine bir Z yazmak için DS'yi geçici olarak B800h yapar. BYTE PTR [0] böylece B8000h'ye gider. İş bitince POP DS eski değeri geri getirir. PUSH ve POP kullanılmasaydı sonraki bütün değişken erişimleri video belleğine giderdi. Daha güvenli bir yol, DS'ye hiç dokunmadan ES'yi kullanmaktır. ES dizgi hedefi dışında hiçbir erişimin varsayılan kesimi değildir.

SS ve SP. İkisi birlikte değişir. SS değiştirildikten sonra SP'nin yeni kesime uygun değeri alması gerekir. İki komutun arasında bir kesme gelseydi işlemci dönüş adresini yeni SS ile eski SP'nin oluşturduğu yanlış bir yere iterdi. 8086 bunu donanımla önler: bir kesim yazmacına MOV ya da POP yapan komuttan sonraki komut bitene kadar kesme kabul edilmez. Bu yüzden MOV SS, AX komutunun hemen arkasına MOV SP, … yazılır ve SS:SP çifti hiçbir an yarım kalmaz.

CS. MOV ile yazılamaz. CS değişirse bir sonraki komut tamamen başka bir yerden getirilir ve IP'nin eski değeri anlamsız kalır. CS bu yüzden IP ile birlikte değişir: uzak JMP, uzak CALL, uzak RET, INT ve IRET komutları ikisini aynı anda yükler. MOV AX, CS gibi okumalar ise serbesttir.

4.1.5Veri türü ve bayt sırası

4.1.5.1byte ptr ve word ptr

Bir bellek adresi tek bir baytı gösterir. 8086 ise aynı adresten başlayarak bir bayt (8 bit) ya da bir sözcük (16 bit, iki bayt) okuyup yazabilir. Komutun hangisini yapacağı makine kodunun en düşük bitinde, W bitinde yazılıdır: W = 0 bayt, W = 1 sözcük demektir. 8A ile 8B işlem kodlarının farkı budur. Assembler bu biti doğru koymak için erişimin boyutunu bilmek zorundadır.

Çoğu komutta boyut diğer işlenenden anlaşılır. MOV [BX], AL komutunda AL 8 bittir ve bir bayt yazılır. MOV [BX], AX komutunda AX 16 bittir ve bir sözcük yazılır. Ama MOV [BX], 5 komutunda iki işlenenin de kendi boyutu yoktur. Köşeli parantez yalnız bir adres söyler. 5 sayısı ise hem bir bayta (05) hem bir sözcüğe (05 00) sığar. Assembler bu durumda karar veremez. Bazı assembler'lar hata verir, bazıları bir boyut tahmin eder. Tahmin yanlışsa program sessizce komşu baytı bozar.

Tanım 4.1.6

Veri türü belirtici (data type specifier), bir bellek işleneninin bayt mı sözcük mü olduğunu assembler'a bildiren ektir. byte ptr [BX] bir baytlık, word ptr [BX] iki baytlık erişim demektir. emu8086 bunların kısa biçimlerini de tanır: b.[SI] bayt, w.[DI] sözcük.

Belirtici yalnız assembler içindir; işlemci onu görmez. MOV BYTE PTR [BX], 5 komutu C6 07 05 (3 bayt), MOV WORD PTR [BX], 5 komutu C7 07 05 00 (4 bayt) olarak kodlanır. Farkın tamamı işlem kodunun W biti (C6 → C7) ve sabitin uzunluğudur. Şekil 4.1.11 aynı adresten iki farklı boyutta okumayı gösterir.

34[BX]12[BX+1]…[BX+2]byte ptr [BX] → 34hword ptr [BX] → 1234h (düşük bayt düşük adreste)
Şekil 4.1.11: Aynı adreste byte ptr bir bayt, word ptr iki bayt okur.
Tablo 4.1.12: Erişim boyutunun nereden anlaşıldığı.
KomutBoyut nereden belli?
MOV [BX], ALAL 8 bit → bayt yazılır
MOV [BX], AXAX 16 bit → sözcük yazılır
MOV [BX], 5belirsiz → MOV BYTE PTR [BX], 5 ya da MOV WORD PTR [BX], 5
MOV AL, sayiAL 8 bit; sayi DB ile tanımlıysa uyumlu, DW ile tanımlıysa tür uyuşmazlığı

Son satır, değişken adının da bir tür taşıdığını gösterir. sayi DB 7 diye tanımlanan bir değişken bayt, DW ile tanımlanan sözcük türündedir. Assembler değişken adı geçen bir komutta boyutu bu türden alır ve yazmaçla uyuşmazsa hata verir. Türü bilerek değiştirmek için yine belirtici yazılır: MOV AL, BYTE PTR sozcuk bir sözcük değişkeninin yalnız düşük baytını okur.

4.1.5.2Kod izleme: byte ptr ve word ptr

Aşağıdaki program aynı adrese farklı boyutlarda yazar ve okur. 0200h'den başlayan dört bayt önceden AA BB CC DD değerlerini taşır. Böylece hangi baytların değiştiği açıkça görülür.

MOV BX, 0200h
MOV WORD PTR [BX], 1234h
MOV BYTE PTR [BX], 0FFh
MOV WORD PTR [BX], 0FFh
MOV AX, [BX]        ; sözcük
MOV CL, [BX+1]      ; bayt
Tablo 4.1.13: byte ptr ve word ptr izlemesi (başlangıçta [0200h…0203h] = AA BB CC DD).
AdımKomutMakine kodu0200h 0201h 0202h 0203hYazmaç
1MOV BX, 0200hBB 00 02AA BB CC DDBX = 0200h
2MOV WORD PTR [BX], 1234hC7 07 34 1234 12 CC DD—
3MOV BYTE PTR [BX], 0FFhC6 07 FFFF 12 CC DD—
4MOV WORD PTR [BX], 0FFhC7 07 FF 00FF 00 CC DD—
5MOV AX, [BX]8B 07FF 00 CC DDAX = 00FFh
6MOV CL, [BX+1]8A 4F 01FF 00 CC DDCL = 00h

Adım 2'de iki bayt yazılır. Sabitin düşük baytı 34h düşük adrese (0200h), yüksek baytı 12h bir sonraki adrese (0201h) gider. Adım 3'te yalnız 0200h değişir ve FFh olur; 0201h'deki 12h yerinde kalır. Adım 4'te aynı FFh sabiti bu kez sözcük olarak yazılır. Sözcük olarak FFh, 00FFh demektir. 0200h'ye FFh, 0201h'ye 00h gider. Önceki adımda korunan 12h bu kez silinmiştir. Sabitin kendisi aynıdır; değişen yalnız belirticidir.

Adım 5'te belirtici gerekmez; AX 16 bit olduğundan bir sözcük okunur. 0200h'deki FFh AL'ye, 0201h'deki 00h AH'ye gider: AX = 00FFh. Adım 6'da CL 8 bittir ve [BX+1] = 0201h'deki tek bayt okunur: CL = 00h. 0202h ve 0203h'deki CC DD baytlarına hiçbir adımda dokunulmamıştır.

BX0200BHBLAX0000AHALCX0000CHCLDS:0200 … DS:02030200FF0201000202CC0203DD
Şekil 4.1.12: Adım 4: WORD PTR ile yazılan 0FFh iki bayta yayılır (FF 00); bir önceki adımda korunan 12h silinir.

4.1.5.3Little-endian düzen

Önceki izlemede sözcüklerin bellekte “ters” durduğu görüldü: 1234h, bellekte 34 12 olarak saklandı. Bu bir rastlantı değil, 8086'nın bayt sırası kuralıdır.

Tanım 4.1.7

Çok baytlı bir değerin düşük baytını düşük adrese, yüksek baytını bir sonraki adrese yazan düzene little-endian (düşük bayt önce) denir. Tersine, yüksek baytı önce yazan düzen big-endian'dır. 8086 ve bütün x86 ailesi little-endian'dır.

AX = 1234h1234yüksek bayt (AH)düşük bayt (AL)0200340201120202…düşük adres → düşük bayt
Şekil 4.1.13: Little-endian: 1234h sözcüğünün düşük baytı 34h düşük adrese, yüksek baytı 12h bir sonraki adrese yazılır.

Kuralın yazmaç düzeyindeki karşılığı çok düzgündür. MOV [0200h], AX komutu AL'yi 0200h'ye, AH'yi 0201h'ye yazar. MOV AX, [0200h] tersini yapar: 0200h'deki bayt AL'ye, 0201h'deki AH'ye gelir. Yazmacın düşük yarısı her zaman düşük adresle eşleşir. Little-endian'ın bir yararı da buradan doğar. Bir sözcük değişkeninin adresinden bir bayt okunursa düşük bayt gelir. 0034h gibi küçük bir sayı, sözcük olarak da bayt olarak da aynı adreste aynı değeri verir.

emu8086'nın bellek penceresi baytları adres sırasıyla gösterir. Bu yüzden sözcükler pencerede ters görünür: 1234h → 34 12. Kural makine kodundaki sabitler için de geçerlidir. MOV AX, 1234h komutu B8 34 12, MOV AX, 0B800h komutu B8 00 B8 olarak kodlanır. Adresler de aynı kurala uyar: MOV AX, [1000h] = A1 00 10.

Sık yapılan hata

Bellek dökümünü soldan sağa okuyup sözcüğü öyle kurmak. 0200h'de 34h, 0201h'de 12h varsa MOV AX, [0200h] sonrası AX = 1234h olur, 3412h değil. Düşük adres düşük bayttır. Aynı yanılgı makine kodunu okurken de yapılır: A1 00 10 komutundaki adres 0010h değil, 1000h'dir.

4.1.5.4Kod izleme: sözcük dizisinde indis

Bayt sırası ve bayt adresleme bir araya geldiğinde sık görülen bir hata ortaya çıkar. Bir sözcük dizisinin i. elemanına erişmek için indis yazmacına i değil, 2i konmalıdır. Aşağıdaki program önce yanlış, sonra doğru yolu izler.

org 100h
mov si, 1            ; indis 1
mov ax, dizi[si]     ; HATA!
shl si, 1            ; indis × 2
mov bx, dizi[si]     ; dizi[1]
mov si, 2            ; indis 2
shl si, 1            ; SI = 4
mov cx, dizi[si]     ; dizi[2]
ret
dizi dw 1234h, 5678h, 9ABCh

Komutların uzunlukları toplandığında dizi 0117h'de başlar. Üç sözcük bellekte little-endian olarak 34 12 78 56 BC 9A diye 0117h–011Ch arasına yerleşir. dizi[0] = 1234h 0117h'de, dizi[1] = 5678h 0119h'de, dizi[2] = 9ABCh 011Bh'dedir.

Tablo 4.1.14: Sözcük dizisinde indis izlemesi (dizi = 0117h: 34 12 78 56 BC 9A).
AdımKomutSIEAOkunan baytlarSonuç
1mov si, 10001h———
2mov ax, dizi[si]0001h0118h12 78AX = 7812h (yanlış)
3shl si, 10002h———
4mov bx, dizi[si]0002h0119h78 56BX = 5678h = dizi[1]
5mov si, 20002h———
6shl si, 10004h———
7mov cx, dizi[si]0004h011BhBC 9ACX = 9ABCh = dizi[2]

Adım 1'de programcı “ikinci eleman” düşüncesiyle SI = 1 verir. Ama indis yazmacı eleman değil bayt sayar. Adım 2'de EA = 0117h + 1 = 0118h olur. Buradan okunan sözcük, dizi[0]'ın yüksek baytı (12h) ile dizi[1]'in düşük baytının (78h) birleşimidir. Little-endian kuralıyla 0118h'deki 12h AL'ye, 0119h'deki 78h AH'ye gider: AX = 7812h. Bu değer dizinin hiçbir elemanı değildir. İşlemci hiçbir uyarı vermez; tek adresten sözcük okumak 8086'da geçerlidir, yalnız bir yol döngüsü fazla sürer.

Adım 3'teki shl si, 1 SI'yı bir bit sola kaydırır, yani 2 ile çarpar: SI = 2. Sözcük dizisinde bayt uzaklığı indis × 2'dir. Adım 4'te EA = 0119h ve BX = 5678h = dizi[1] doğru gelir. Adım 5 ve 6 aynı işi indis 2 için yapar: SI = 2, sonra 4. Adım 7'de EA = 011Bh ve CX = 9ABCh = dizi[2] olur. Kaydırma, 2 ile çarpmanın en kısa ve hızlı yoludur; D1 E6 iki baytlık bir komuttur.

34011712011878011956011ABC011B9A011Cdizi[0]dizi[1]dizi[2]SI0001AX7812BX0000CX0000EA = 0117 + 0001 = 0118
Şekil 4.1.14: SI = 1 ile dizi[si] iki elemanın ortasından okur: 0118h'deki 12h ve 0119h'deki 78h birleşir, AX = 7812h.

shl komutu MOV'dan farklı olarak bayrakları da günceller. 1'i bir bit kaydırmak 2 verir; dışarı çıkan bit 0 olduğundan CF = 0 olur, sonuç sıfır olmadığından ZF = 0'dır. Yardımcı elde bayrağı AF kaydırma komutlarından sonra tanımsızdır. Döngüyle bir sözcük dizisi gezilirken SI her turda ADD SI, 2 ile ilerletilir. INC SI yalnız bayt dizileri içindir.

4.1.6MOV komutu

4.1.6.1Tanım ve kurallar

Önceki bütün örneklerde kullanılan MOV, 8086'nın en sık kullanılan komutudur. Derleyicilerin ürettiği kodun önemli bir kısmı yalnız MOV'lardan oluşur.

Tanım 4.1.8

MOV hedef, kaynak komutu kaynaktaki değeri hedefe kopyalar. Kaynak değişmez. Kaynak bir anlık değer (sabit), genel amaçlı yazmaç, kesim yazmacı ya da bellek konumu olabilir. Hedef ise genel amaçlı yazmaç, kesim yazmacı (CS hariç) ya da bellek konumudur.

MOV'un kuralları beş maddede toplanır:

  1. CS ve IP'ye MOV ile değer atanmaz. CS kaynak olarak okunabilir; IP hiçbir MOV'da yer almaz.
  2. İki işlenenin boyutu aynı olmalıdır: ikisi de bayt ya da ikisi de sözcük.
  3. İki işlenen birden bellek olamaz.
  4. Kesim yazmacına anlık değer yüklenemez ve bir kesim yazmacı diğerine doğrudan kopyalanamaz.
  5. MOV bayrakları etkilemez.
REGSREGMEMIMM✗MEM ↔ MEM ✗SREG ↔ MEMREG → REG
Şekil 4.1.15: MOV için izin verilen kaynak → hedef yönleri. Bellek ile bellek, sabit ile kesim yazmacı ve iki kesim yazmacı arasında ok yoktur.

Kuralların çoğu makine kodunun yapısından gelir. Bir MOV komutunda en çok bir ModR/M baytı bulunur ve bu bayt yalnız bir bellek işleneni tanımlayabilir. İkinci işlenen REG alanındaki bir yazmaçtır ya da komutun sonundaki bir sabittir. İki bellek işleneni için yer yoktur. Kesim yazmaçları için ayrı işlem kodları vardır: 8E kesim yazmacına, 8C kesim yazmacından taşır. Bunların ikinci işleneni her zaman ModR/M ile seçilen bir genel yazmaç ya da bellek sözcüğüdür. Bu yüzden kesimden kesime ya da sabitten kesime komut yoktur.

Bayrakların değişmemesi de bilinçli bir seçimdir. Bir karşılaştırmanın ardından, koşullu atlamadan önce bir değeri yazmaca almak gerekebilir. MOV bayrakları bozsaydı karşılaştırmanın sonucu kaybolurdu.

Sunumdaki iki örnek kuralları uygular. MOV AX, BX BX'teki değeri AX'e kopyalar; BX değişmez. MOV [SI], 10h ise SI'nın gösterdiği DS:SI adresine 10h yazmak ister. Hedef bir bellek konumu, kaynak bir sabittir ve boyut belirsizdir. Doğru yazım MOV BYTE PTR [SI], 10h'dir.

4.1.6.2Desteklenen işlenenler

emu8086 belgeleri MOV'un geçerli biçimlerini iki grupta listeler. Tablo 4.1.15 bu listeyi, yazımda kullanılan kısaltmaların anlamlarıyla verir.

Tablo 4.1.15: MOV komutunun desteklenen işlenen birleşimleri.
Genel amaçlıKesim yazmaçlarıyla
MOV REG, memoryMOV SREG, memory
MOV memory, REGMOV memory, SREG
MOV REG, REGMOV REG, SREG
MOV memory, immediateMOV SREG, REG
MOV REG, immediate—
  • REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
  • SREG: DS, ES, SS ve CS. CS yalnız ikinci işlenen, yani kaynak olabilir.
  • memory: [BX], [BX+SI+7], bir değişken adı ve 24 biçimin herhangi biri.
  • immediate: 5, −24, 3Fh, 10001101b gibi sabitler.

MOV SREG, immediate ve MOV SREG, SREG biçimleri yoktur. Değer önce bir genel yazmaca alınır: MOV AX, 0B800h ardından MOV DS, AX. Kesimden kesime kopyalama için iki yol vardır: MOV AX, ES / MOV DS, AX ya da PUSH ES / POP DS. İkinci yol bir genel yazmacı bozmaz ama yığını kullanır.

4.1.6.3Geçerli mi?

Kurallar on komut üzerinde sınanabilir. Tablo 4.1.16 her komutun durumunu ve gerekçesini verir. Geçersiz komutların hepsinde assembler hata verir.

Tablo 4.1.16: On MOV komutunun geçerliliği.
NoKomutDurumGerekçe ve doğrusu
1MOV [BX], [SI]geçersizbellekten belleğe MOV yok → MOV AL, [SI] · MOV [BX], AL
2MOV DS, ESgeçersizkesimden kesime yok → MOV AX, ES · MOV DS, AX ya da PUSH ES · POP DS
3MOV DS, 100hgeçersizkesime sabit atanamaz
4MOV CS, AXgeçersizCS hedef olamaz (uzak JMP kullanılır); IP de yazılamaz (MOV IP, AX yerine JMP AX)
5MOV [BX], 5geçersizboyut belirsiz → BYTE PTR / WORD PTR
6MOV AX, CSgeçerliCS kaynak olabilir; kodu 8C C8
7MOV SP, BXgeçerliSP genel bir yazmaçtır; ama yığını başka yere taşır
8MOV BL, DXgeçersiz8 ve 16 bit uyuşmaz
9MOV AL, [SI+BP]geçerli[BP+SI] ile aynı; kesim SS
10MOV 5, AXgeçersizhedef sabit olamaz

7. komut üzerinde biraz durmak gerekir. Komut kurallara uyar ve assembler onu kabul eder. Ama SP'nin değeri değiştiği anda yığının yeri de değişir. Bundan sonraki ilk PUSH, CALL ya da gelen bir kesme veriyi BX'in gösterdiği yere yazar. Bu satır bilerek yazılmadıysa program çoğu zaman RET komutunda yanlış bir adrese döner. 9. komut ise yazım sırasının önemsiz olduğunu hatırlatır: [SI+BP], BP içerdiği için SS kesimine gider.

4.1.6.4Kod izleme: yazmaç üzerinden blok kopyalama

Bellekten belleğe MOV olmadığına göre bir bellek bloğunu başka bir yere kopyalamak için her bayt bir yazmaçtan geçirilir. Aşağıdaki program dört baytlık kaynak dizgisini hedef tamponuna kopyalar.

org 100h
mov si, offset kaynak
mov di, offset hedef
mov cx, 4
kopya:
mov al, [si]         ; bellek → AL
mov [di], al         ; AL → bellek
inc si
inc di
loop kopya
ret
kaynak db 'ABCD'
hedef  db 4 dup('.')

Kod 0100h–0111h arasındaki 18 bayttır. kaynak 0112h'de, hedef 0116h'de başlar. 4 dup('.') dört nokta karakteri (2Eh) ayırır. loop kopya komutu CX'i bir azaltır ve CX sıfır değilse kopya etiketine atlar. Makine kodu E2 F8'dir: LOOP 010Fh'de, sonraki komut 0111h'dedir ve 0111h + (−8) = 0109h, yani kopya'nın adresidir. Atlama göreceli moddadır.

Tablo 4.1.17: Blok kopyalamanın izlemesi (kaynak = 0112h: 'ABCD', hedef = 0116h: '....').
AdımKomutSIDICXALhedef
1mov si, offset kaynak0112h0000h0000h00h....
2mov di, offset hedef0112h0116h0000h00h....
3mov cx, 40112h0116h0004h00h....
4mov al, [si]0112h0116h0004h41h....
5mov [di], al0112h0116h0004h41hA...
6inc si0113h0116h0004h41hA...
7inc di0113h0117h0004h41hA...
8loop kopya0113h0117h0003h41hA...
9–13tur 20114h0118h0002h42hAB..
14–18tur 30115h0119h0001h43hABC.
19–23tur 40116h011Ah0000h44hABCD
24ret0116h011Ah0000h44hABCD

İlk üç adım iki işaretçiyi ve sayacı kurar. SI kaynağın, DI hedefin bağıl konumunu tutar; iki işaretçi iki ayrı tamponu gösterir. CX = 4 kopyalanacak bayt sayısıdır. Adım 4'te mov al, [si] bellekten yazmaca taşır ve AL = 'A' = 41h olur. Adım 5'te mov [di], al yazmaçtan belleğe taşır ve 0116h'ye 41h yazılır. AL burada bir ara duraktır. Bellekten belleğe MOV olmadığı için başka yolu yoktur.

Adım 6 ve 7'de iki işaretçi birlikte bir bayt ilerler. Adım 8'de LOOP, CX'i 3'e indirir. CX sıfır olmadığından IP = 0109h olur ve döngü başa döner. İkinci, üçüncü ve dördüncü turlar aynı beş adımı tekrarlar; tabloda her tur tek satırda özetlenmiştir. Dördüncü turun sonunda CX = 0 olur ve LOOP atlamaz; program ret'e düşer. Hedef artık “ABCD” içerir. SI ve DI tamponların hemen arkasını gösterir: SI = 0116h, DI = 011Ah. SI'nın son değeri rastlantı eseri hedef'in başlangıcıdır, çünkü iki tampon bitişiktir.

kaynak'A'0112'B'0113'C'0114'D'0115hedef'A'0116'.'0117'.'0118'.'0119SIDIAL'A'CX0004
Şekil 4.1.16: Blok kopyalamanın 5. adımı: AL'deki 'A' (41h), DI'nın gösterdiği 0116h'ye yazılır.

MOV bayrakları değiştirmez, ama INC değiştirir. Bayrak durumu bu programda hiçbir kararı etkilemez. LOOP, bayraklara bakmaz; yalnız CX'e bakar. Yine de izlemede eşlik bayrağının INC'lerle değiştiği görülür. Örneğin inc di ile DI = 0117h olduğunda düşük bayt 17h = 0001 0111b'dir. Dört adet 1 biti bulunduğundan PF = 1 olur.

Her bayt için iki bellek erişimi, iki işaretçi artırma ve bir döngü komutu gerekir. Bu iş çok sık yapıldığı için 8086'da ayrı bir komut vardır: REP MOVSB, DS:SI'dan ES:DI'ya CX bayt kopyalar ve işaretçileri kendisi ilerletir. Aynı program dizgi komutlarıyla CLD, REP MOVSB satırlarına iner.

4.1.7Program örneği: ekrana 'A' yazmak

4.1.7.1Program ve makine kodu

Buraya kadar anlatılanlar küçük bir programda bir araya gelir. Program, renkli metin ekranının video belleğine doğrudan bir karakter yazar. İşletim sisteminin hiçbir hizmeti kullanılmaz; ekrana yazmak, belirli bir bellek adresine bir sözcük koymaktan ibarettir.

ORG 100h          ; .com programı için
MOV AX, 0B800h    ; AX = B800h
MOV DS, AX        ; DS = B800h
MOV CL, 'A'       ; CL = 41h
MOV CH, 11011111b ; CH = DFh
MOV BX, 15Eh      ; BX = 015Eh
MOV [BX], CX      ; B800:015E ← CX
RET               ; DOS'a dön

Programın her satırı bir öğeyi tanıtır. ORG bir yönergedir; programın başlangıç adresini belirler ve makine koduna çevrilmez. Noktalı virgülden sonrası açıklamadır; assembler onu yok sayar. MOV kaynak ile hedef arasında değer kopyalar. DS'ye sabit doğrudan atanamadığı için B800h önce AX'e yüklenir. 'A' karakter sabitidir ve ASCII kodu 41h ile aynıdır. 11011111b ikili yazılmış bir sabittir ve DFh'ye eşittir. MOV [BX], CX CX'teki sözcüğü DS:BX adresine yazar.

Tablo 4.1.18: Programın makine kodu (0100h'den başlayarak 15 bayt).
AdresKomutMakine koduAçıklama
0100hMOV AX, 0B800hB8 00 B8B8 = “AX'e anlık sözcük”; sabit little-endian
0103hMOV DS, AX8E D88E = kesim yazmacına; D8 = 11 011 000 (DS ← AX)
0105hMOV CL, 'A'B1 41B0 + 1 (CL); 41h = 'A'
0107hMOV CH, 11011111bB5 DFB0 + 5 (CH)
0109hMOV BX, 15EhBB 5E 01B8 + 3 (BX)
010ChMOV [BX], CX89 0F89 = yazmaçtan belleğe sözcük; 0F = 00 001 111
010EhRETC3yakın dönüş

Tablodaki kodlarda düzenli bir yapı göze çarpar. Bir yazmaca anlık değer yükleyen MOV'un işlem kodu, bayt yazmaçları için B0'dan, sözcük yazmaçları için B8'den başlar ve yazmacın üç bitlik numarası eklenir. Numaralar AL/AX = 0, CL/CX = 1, DL/DX = 2, BL/BX = 3, AH/SP = 4, CH/BP = 5, DH/SI = 6, BH/DI = 7'dir. CL için B1, CH için B5, BX için BB böylece bulunur. Bu komutlarda ModR/M baytı yoktur; yazmaç işlem kodunun içine gömülüdür.

4.1.7.2Kod izleme

Program emu8086'da bir COM programı olarak çalışır. Başlangıçta CS = DS = ES = SS = 0700h, IP = 0100h ve SP = FFFEh'dir. Ekranın bütün hücreleri boştur: her hücrede 20h (boşluk) ve 07h (siyah zemin üzerine gri yazı) baytları vardır.

Tablo 4.1.19: Ekrana 'A' yazan programın izlemesi.
AdımKomutAXDSCXBX[B800:015E] [015F]
0(başlangıç)0000h0700h0000h0000h20h 07h
1MOV AX, 0B800hB800h0700h0000h0000h20h 07h
2MOV DS, AXB800hB800h0000h0000h20h 07h
3MOV CL, 'A'B800hB800h0041h0000h20h 07h
4MOV CH, 11011111bB800hB800hDF41h0000h20h 07h
5MOV BX, 15EhB800hB800hDF41h015Eh20h 07h
6MOV [BX], CXB800hB800hDF41h015Eh41h DFh
7RETB800hB800hDF41h015Eh41h DFh

Adım 1'de AX = B800h olur. B800h, renkli metin ekranının kesimidir; fiziksel olarak B8000h'de başlar. Adım 2'de DS = B800h olur. Bundan sonra köşeli parantezle yapılan bütün öneksiz veri erişimleri video belleğine gider. Program bu noktadan sonra kendi değişkenlerine DS ile erişemez; bu küçük programın değişkeni olmadığı için sorun çıkmaz.

Adım 3 ve 4 CX'in iki yarısını ayrı ayrı doldurur. CL = 41h karakterin ASCII kodu, CH = DFh renk (öznitelik) baytıdır. İki yarı birlikte okununca CX = DF41h olur. Adım 5'te BX = 015Eh = 350 olur. Bu sayı ekrandaki konumun video belleğindeki bağıl adresidir.

Adım 6 programın asıl işidir. MOV [BX], CX bir sözcük yazar. Little-endian kuralıyla CL (41h) düşük adrese, B800:015Eh'ye; CH (DFh) yüksek adrese, B800:015Fh'ye gider. Fiziksel adresler B8000h + 015Eh = B815Eh ve B815Fh'dir. Karakter baytının önce, renk baytının sonra gelmesi video belleğinin düzenine tam uyar. Bu yüzden karakter düşük yarıya, renk yüksek yarıya konmuştur. Ekran kartı bu iki baytı bir sonraki tarama sırasında okur ve hücrede renkli bir 'A' görünür.

AXB800AHALCXDF41CHCLBX015EBHBLDSB800B800:015C … 015F (video belleği)015C20015D07015E41015FDF
Şekil 4.1.17: Adım 6: CX = DF41h sözcük olarak yazılır; [015Eh] = 41h ('A'), [015Fh] = DFh (renk). Fiziksel adres B815Eh.

Adım 7'de RET yığının tepesindeki 0000h değerini IP'ye alır ve SP = 0000h olur. 0700:0000'daki INT 20h programı bitirir. Harf ekranda kalır, çünkü video belleği programdan bağımsızdır. DS'nin B800h kalması da bir sorun yaratmaz; DOS program bittikten sonra kendi yazmaçlarını yeniden kurar.

4.1.7.3Metin modu video belleği

80 × 25 metin modunda ekran 25 satır ve 80 sütundan oluşur. Her hücre video belleğinde 2 bayt tutar: önce karakter, sonra renk. Bir satır 80 × 2 = 160 bayttır ve bütün ekran 25 × 160 = 4000 bayt kaplar. Satır ve sütun 0'dan sayılırsa bir hücrenin bağıl adresi şöyle bulunur:

bağıl adres = (satır × 80 + sütun) × 2

Programdaki 015Eh bu formülden gelir: (2 × 80 + 15) × 2 = 175 × 2 = 350 = 15Eh. Harf 2. satırın 15. sütununa yazılmıştır (Şekil 4.1.18). Ters yönde de hesap yapılabilir. 015Eh = 350 ikiye bölünür: 175. 175 = 2 × 80 + 15 olduğundan satır 2, sütun 15'tir.

Asütun 079024satır 2, sütun 15
Şekil 4.1.18: 80 × 25 metin ekranı. Satır 2, sütun 15'teki hücreye macenta zemin üzerine parlak beyaz bir 'A' yazılmıştır.

Öznitelik baytının bitleri rengi kodlar. DFh = 1101 1111b şöyle okunur:

  • Bit 7 = 1: gerçek ekranda karakterin yanıp sönmesi; emu8086'da parlak zemin.
  • Bit 6–4 = 101: zemin rengi macenta (5).
  • Bit 3–0 = 1111: yazı rengi parlak beyaz (15).

Yazı rengi dört bitle 16 renkten birini, zemin rengi üç bitle 8 renkten birini seçer. Temel renkler 0 siyah, 1 mavi, 2 yeşil, 3 camgöbeği, 4 kırmızı, 5 macenta, 6 kahverengi, 7 açık gri'dir; 8–15 bunların parlak hâlleridir ve 14 sarıdır. Önceki örnekteki 1Eh böylece mavi zemin (001) üzerine sarı yazı (1110), 07h ise siyah zemin üzerine gri yazı demektir.

Örnek 4.1.3

Ekranın 10. satırının 40. sütununa yeşil zemin üzerine sarı bir 'X' yazan kod nasıl olur? Renk baytı 2Eh'dir.

Bağıl adres (10 × 80 + 40) × 2 = 840 × 2 = 1680 = 690h'dir. 'X' karakterinin ASCII kodu 58h'dir. Karakter düşük, renk yüksek baytta olacağından yazılacak sözcük 2E58h'dir. 2Eh = 0010 1110b: zemin 010 (yeşil), yazı 1110 (sarı).

MOV AX, 0B800h
MOV DS, AX
MOV BX, 690h
MOV WORD PTR [BX], 2E58h

Son komutta WORD PTR gereklidir; aksi hâlde sabitin boyutu belirsiz kalır. Kod B8690h'ye 58h, B8691h'ye 2Eh yazar.

4.1.8MOV örnekleri

emu8086 belgelerindeki kısa MOV örnekleri her biri tek bir veri yolunu gösterir: bellekten yazmaca, yazmaçtan belleğe, yazmaçtan yazmaca, sabitten belleğe. Aşağıdaki kesimler bunları sırayla izler. Hepsi COM programıdır; başlangıçta CS = DS = 0700h, IP = 0100h'dir.

4.1.8.1Bellekten yazmaca

ORG 100h
MOV AX, [1000h]   ; A1 00 10
RET

DS:1000h adresinde önceden CD AB baytları bulunsun. Komut doğrudan adreslemeyle bu iki baytı okur. Little-endian kuralıyla 1000h'deki CDh AL'ye, 1001h'deki ABh AH'ye gider: AX = ABCDh. Komut üç bayttır; yürütüldükten sonra IP = 0103h olur. Fiziksel adres 07000h + 1000h = 08000h'dir. Bellek değişmez; MOV yalnız kopyalar.

Tablo 4.1.20: Bellekten yazmaca izlemesi (DS:1000h = CD AB).
AdımKomutAXIP (sonra)[1000h] [1001h]
0(başlangıç)0000h0100hCD AB
1MOV AX, [1000h]ABCDh0103hCD AB
2RETABCDh0000hCD AB

Bu programın emu8086 penceresindeki görünümü üç bölümden oluşur. Solda yazmaçlar vardır; AX, BX, CX ve DX'in yüksek ve düşük yarıları (H, L) ayrı kutularda gösterilir. Başlangıçta CS = DS = 0700h, IP = 0100h, SP = FFFEh'dir. Ortada bellek dökümü bulunur. 07100h fiziksel adresi, yani 0700:0100, komutun üç baytını (A1 00 10) taşır. Sağda ayrıştırılmış (disassembled) kod yer alır: MOV AX, [01000h] ve ardından RET (C3). single step düğmesi bir komutu yürütür ve değişen yazmaçlar renkle vurgulanır. Gerçek emu8086'da DS:1000h bölgesi başlangıçta sıfırdır; bu yüzden pencerede komut çalıştıktan sonra AX = 0000h kalır. ABCDh değeri, belleğe önceden CD AB yazıldığı varsayımıyla elde edilir.

4.1.8.2Yazmaçtan belleğe

ORG 100h
MOV BX, 1234h     ; BB 34 12
MOV [2000h], BX   ; 89 1E 00 20
RET
Tablo 4.1.21: Yazmaçtan belleğe izlemesi (DS:2000h başlangıçta 00 00).
AdımKomutBXIP (sonra)[2000h] [2001h]
0(başlangıç)0000h0100h00 00
1MOV BX, 1234h1234h0103h00 00
2MOV [2000h], BX1234h0107h34 12
3RET1234h0000h34 12

Birinci komut BX'e anlık değer yükler. İkinci komut BX'i doğrudan adrese yazar: BL (34h) 2000h'ye, BH (12h) 2001h'ye. Bu komut dört bayttır. AX dışındaki bir yazmaç kullanıldığı için kısa A3 biçimi seçilemez. Genel 89 işlem kodu, ModR/M baytı ve iki adres baytı gerekir. ModR/M baytı 1E = 00 011 110 olarak okunur: REG = BX, R/M = doğrudan adres. IP 0103h'den 0107h'ye ilerler. BX değişmez. Fiziksel adres 07000h + 2000h = 09000h'dir.

Son adımdaki RET, yığının tepesinden COM programının dönüş adresini (0000h) çeker. Bu yüzden RET'ten sonraki IP 0000h'dir; program bir sonraki komutu 0700:0000'dan, yani PSP'nin başındaki INT 20h'den alır. Bütün COM örneklerinde son adım böyledir.

4.1.8.3XCHG: takas

İki değerin yerini değiştirmek sıralama gibi pek çok algoritmanın temel işlemidir. 8086'da bunun için ayrı bir komut vardır.

Tanım 4.1.9

XCHG hedef, kaynak komutu iki işlenenin içeriğini tek bir komutta karşılıklı değiştirir (exchange). İşlenenlerden biri yazmaç, diğeri yazmaç ya da bellek olabilir. Bellek ile bellek, kesim yazmaçları ve sabitler kullanılamaz. İki işlenenin boyutu aynı olmalıdır. XCHG bayrakları etkilemez.

MOV CX, 10   ; CX = 000Ah
MOV DX, 20   ; DX = 0014h
XCHG CX, DX  ; takas

Sayılar sonek taşımadığında onluk kabul edilir. Birinci komuttan sonra CX = 10 = 000Ah, ikinciden sonra DX = 20 = 0014h olur. XCHG ardından CX = 0014h ve DX = 000Ah'dir. Bayraklar değişmez. Komutun makine kodu 87 CA'dır: 87 sözcük takası, CA = 11 001 010 ise REG = CX, R/M = DX'tir.

Tablo 4.1.22: İki yazmacın takası.
AdımKomutCXDX
1MOV CX, 10000Ah0000h
2MOV DX, 20000Ah0014h
3XCHG CX, DX0014h000Ah

4.1.8.4XCHG kuralları

  • Yazmaç ↔ yazmaç: XCHG AX, BX.
  • Yazmaç ↔ bellek: XCHG AL, [SI]. Yazım sırası önemsizdir; XCHG [SI], AL aynı komuttur.
  • Bellek ↔ bellek yoktur.
  • Kesim yazmaçları ve sabitler kullanılamaz. Sabitle takas zaten anlamsızdır: bir sabitin içine değer yazılamaz.
  • Boyutlar aynı olmalıdır; bayraklar değişmez.
  • XCHG AX, reg biçimi tek baytlık özel bir koda sahiptir: 90h + yazmaç numarası. XCHG AX, BX = 93. XCHG AX, AX hiçbir şeyi değiştirmez ve kodu 90'dır. Bu bayt aynı zamanda NOP (işlem yok) komutudur.

XCHG olmasaydı takas için geçici bir yazmaç gerekirdi:

MOV AX, CX    ; AX ← CX (yedek)
MOV CX, DX    ; CX ← DX
MOV DX, AX    ; DX ← eski CX

Bu yol üç komut ve bir yazmaç daha harcar. AX'in eski değeri de kaybolur. Süre açısından da XCHG öndedir. 8086'da yazmaçtan yazmaca MOV 2 tur, XCHG ise 4 turdur; üç MOV 6 tur tutar. AX ile yapılan tek baytlık takas 3 turdur. Yazmaç ile bellek arasındaki takas ise pahalıdır: 17 tur artı EA süresi. Bunun nedeni, işlemcinin önce bellekten okuyup sonra belleğe yazmasıdır; iki ayrı yol döngüsü gerekir.

XCHG'nin bellekle kullanımının çok işlemcili sistemlerde ayrı bir önemi vardır. Okuma ve yazma tek komutta yapıldığı için arada başka bir işlemcinin aynı bayta erişme fırsatı daralır. LOCK önekiyle birlikte kullanıldığında 8086, LOCK̅ pinini komut boyunca etkin tutar ve yolu başka bir yol ustasına bırakmaz. Bir kaynağı aynı anda yalnız bir işlemcinin kullanmasını sağlayan kilitler bu düzene dayanır.

4.1.8.5Kod izleme: XCHG ile takas

Aşağıdaki program XCHG'nin bellekle kullanımını ve aynı takasın XCHG ile ve XCHG olmadan yapılışını yan yana gösterir.

ORG 100h
MOV SI, OFFSET sayi
MOV AL, 5Ah
XCHG AL, [SI]      ; AL ↔ [SI]
MOV CX, 1111h
MOV DX, 2222h
MOV AX, CX         ; yedek
MOV CX, DX
MOV DX, AX         ; takas
XCHG CX, DX        ; tek komut
RET
sayi DB 0A5h
Tablo 4.1.23: XCHG ile takasın izlemesi (sayi = 0116h, başlangıçta A5h).
AdımKomutAXCXDXSIsayi
1MOV SI, OFFSET sayi0000h0000h0000h0116hA5h
2MOV AL, 5Ah005Ah0000h0000h0116hA5h
3XCHG AL, [SI]00A5h0000h0000h0116h5Ah
4MOV CX, 1111h00A5h1111h0000h0116h5Ah
5MOV DX, 2222h00A5h1111h2222h0116h5Ah
6MOV AX, CX1111h1111h2222h0116h5Ah
7MOV CX, DX1111h2222h2222h0116h5Ah
8MOV DX, AX1111h2222h1111h0116h5Ah
9XCHG CX, DX1111h1111h2222h0116h5Ah

Adım 1'de SI, sayi değişkeninin bağıl konumunu (0116h) alır. Bellekte sayi = A5h'dir. Adım 2'de AL = 5Ah olur. Adım 3'teki XCHG AL, [SI] (86 04) bir yazmaçla bir bellek baytını takas eder: AL = A5h, sayi = 5Ah. Ara yazmaç gerekmemiştir. Bu tek komut, belleği okuyan ve belleğe yazan iki yol döngüsünü birlikte içerir.

Adım 4 ve 5 CX ve DX'e tanınabilir değerler koyar. Adım 6–8 aynı takası XCHG olmadan yapar. Adım 6'da CX'in yedeği AX'e alınır; AX'in önceki değeri (00A5h) kaybolur. Adım 7'de CX = 2222h olur. Bu anda CX'in eski değeri yalnız AX'te durur. Adım 8'de DX = 1111h olur ve takas tamamlanır. Üç komut ve bir yazmaç harcanmıştır. Adım 9'daki tek XCHG CX, DX takası geri alır: CX = 1111h, DX = 2222h. Bu sırada AX'e dokunulmaz.

AX00A5hCX0000hDX0000hsayi · 0116h5AhAL ↔ [SI]
Şekil 4.1.19: Adım 3: XCHG AL, [SI] yazmaç ile bellek baytını tek komutta takas eder; AL = A5h, sayi = 5Ah.

4.1.8.6Yazmaçtan yazmaca

MOV SI, 3000h  ; SI = adres
MOV DI, SI     ; DI = SI
MOV AL, [SI]   ; DS:3000h
MOV [DI+1], AL ; DS:3001h

Bu örnek, adres tutan yazmaçlar arasında kopyalamanın ne anlama geldiğini gösterir. DS:3000h'de 5Ah bulunsun. Birinci komut SI'ya bir bağıl konum (3000h) atar. İkinci komut MOV DI, SI ile DI = 3000h olur. Kopyalanan şey adrestir, bellekteki veri değil. Artık iki yazmaç aynı hücreyi gösterir. Üçüncü komut [SI] ile 5Ah'yi okur: AL = 5Ah. Dördüncü komut bunu [DI+1] = 3001h'ye yazar. Bellekte 3000h–3001h artık 5A 5A'dır.

Tablo 4.1.24: Yazmaçtan yazmaca izlemesi (DS:3000h = 5Ah).
AdımKomutMakine koduSIDIAL[3000h] [3001h]
1MOV SI, 3000hBE 00 303000h0000h00h5A ??
2MOV DI, SI8B FE3000h3000h00h5A ??
3MOV AL, [SI]8A 043000h3000h5Ah5A ??
4MOV [DI+1], AL88 45 013000h3000h5Ah5A 5A

C dilinde bu, iki işaretçiyi eşitlemeye benzer: q = p; ardından q[1] = p[0];. İşaretçilerin kendisi kopyalanır, gösterdikleri veri değil.

4.1.8.7Belleğe sabit yazma

ORG 100h
MOV BYTE PTR [4000h], 65  ; 'A'
MOV WORD PTR [4002h], 65
RET

DS:4000h–4003h başlangıçta 00 99 00 99 olsun. Birinci komut 65'i tek bayt olarak yazar. 65 = 41h, 'A' harfinin ASCII kodudur. Makine kodu C6 06 00 40 41'dir ve beş bayt tutar: işlem kodu, ModR/M, iki adres baytı ve bir veri baytı. IP 0105h olur. 4001h değişmez.

İkinci komut aynı sabiti WORD PTR ile yazar. 65 artık 0041h sözcüğüdür; 4002h'ye 41h, 4003h'ye 00h gider. 4003h'deki 99h silinmiştir. Komut C7 06 02 40 41 00 diye altı bayttır ve IP 010Bh'ye ilerler. Sabitin kendi boyutu yoktur; boyutu PTR belirticisi belirler. Kaynak koddaki 65 sayısı iki komutta da aynıdır ama makine koduna bir kez bir, bir kez iki bayt olarak girer.

Tablo 4.1.25: Belleğe sabit yazmanın izlemesi (DS:4000h = 00 99 00 99).
AdımKomutIP (sonra)4000h 4001h 4002h 4003h
0(başlangıç)0100h00 99 00 99
1MOV BYTE PTR [4000h], 650105h41 99 00 99
2MOV WORD PTR [4002h], 65010Bh41 99 41 00
3RET0000h41 99 41 00

4.1.8.88 bitlik yarılarla çalışmak

AX, BX, CX ve DX'in her birinin iki 8 bitlik yarısı ayrı yazmaç adlarıyla kullanılabilir: AH ve AL, BH ve BL gibi. Bir yarıya yazmak diğer yarıyı etkilemez. Bu, iki küçük değeri tek bir yazmaçta tutmaya ve bir sözcüğün baytlarını ayrı ayrı işlemeye olanak verir.

Düşük baytı kopyalama. Aşağıdaki kodda AL, BL'ye kopyalanır.

MOV AX, 1234h   ; AH = 12h, AL = 34h
MOV BX, 0FFFFh
MOV BL, AL      ; yalnız BL

Birinci komut AX = 1234h yapar: AH = 12h, AL = 34h. İkinci komut, etkinin görülebilmesi için BX'i FFFFh ile doldurur. Üçüncü komut (8A D8) yalnız BL'yi değiştirir: BL = 34h. BH = FFh yerinde kalır ve BX = FF34h olur. 16 bitlik bir yazmaçtan 8 bitlik bir yazmaca kopyalama (MOV BL, AX) geçersizdir; boyutların aynı olması gerekir.

Yüksek bayta ekleme. Yarılar üzerinde aritmetik yapıldığında eldenin bir yarıdan diğerine geçmediği görülür.

MOV AX, 00FFh   ; AH = 00h, AL = FFh
ADD AH, 01h     ; yalnız AH
ADD AL, 01h     ; yalnız AL
MOV AX, 01FFh
ADD AX, 1       ; 16 bit
Tablo 4.1.26: Yüksek ve düşük bayta ekleme (bayraklar: CF, ZF, SF, AF, PF).
AdımKomutMakine koduAXCFZFSFAFPF
1MOV AX, 00FFhB8 FF 0000FFh00000
2ADD AH, 01h80 C4 0101FFh00000
3ADD AL, 01h04 010100h11011
4MOV AX, 01FFhB8 FF 0101FFh11011
5ADD AX, 105 01 000200h00011

Adım 2'de AH = 00h + 01h = 01h olur ve AX = 01FFh'dir. Sonuç sıfır değildir ve elde yoktur. 01h'de tek sayıda 1 biti olduğundan PF = 0'dır. Adım 3'te AL = FFh + 01h hesaplanır. 8 bitlik sonuç 00h'dir ve dokuzuncu bit olarak bir elde çıkar: CF = 1, ZF = 1. Düşük dört bitten de elde çıktığı için AF = 1 olur. 00h'de sıfır tane 1 vardır; sıfır çift sayıdır ve PF = 1 olur. Elde AH'ye geçmez: AX = 0100h. Bu bir 8 bitlik toplamadır ve AH işlemin parçası değildir.

Adım 4'te AX yeniden 01FFh yapılır. MOV bayrakları değiştirmediği için önceki adımın bayrakları (CF = 1, ZF = 1) aynen kalır. Adım 5'teki 16 bitlik toplamada 01FFh + 1 = 0200h olur. Bu kez elde AL'den AH'ye geçmiştir, çünkü işlem 16 bittir. 16 bitten taşan elde olmadığından CF = 0'dır. AF yine 1'dir; düşük dört bitte F + 1 elde üretir. PF yalnız sonucun düşük baytına bakar: 00h için PF = 1. ADD AX, 1 komutu AX'e özgü kısa biçimle 05 01 00 diye kodlanır.

Sık yapılan hata

8 bitlik bir toplamanın eldesinin yazmacın diğer yarısına geçeceğini sanmak. ADD AL, 1 AL = FFh iken AH'yi artırmaz; yalnız CF = 1 olur. 16 bitlik bir değere 8 bitlik parçalar hâlinde ekleme yapılacaksa yüksek yarıda ADC (eldeyle topla) kullanılır: ADD AL, 1 ardından ADC AH, 0.

4.1.8.9Sayı tabanlarıyla atama

Assembly kaynak kodunda sabitler farklı tabanlarda yazılabilir. Hangi taban kullanılırsa kullanılsın, assembler sayıyı ikili değere çevirip makine koduna yazar. Aşağıdaki program üç tabanı birlikte kullanır.

mov al, 00000101b ; ikili
mov bl, 0ah       ; onaltılık
mov cl, 10o       ; sekizli
add al, bl        ; 5 + 10 = 15
sub al, cl        ; 15 - 8 = 7
Tablo 4.1.27: Sayı tabanlarıyla atamanın izlemesi.
AdımKomutMakine koduALBLCLCFPF
1mov al, 00000101bB0 0505h00h00h00
2mov bl, 0ahB3 0A05h0Ah00h00
3mov cl, 10oB1 0805h0Ah08h00
4add al, bl02 C30Fh0Ah08h01
5sub al, cl2A C107h0Ah08h00

00000101b ikili sayısı 5'tir ve AL = 05h olur. 0Ah onaltılık sayısı 10'dur; harfle başladığı için önüne 0 yazılmıştır. 10o sekizli sayısı 1 × 8 + 0 = 8'dir ve CL = 08h olur. Makine kodlarında sabitler artık tabandan bağımsızdır: 05, 0A, 08. Adım 4'te AL = 5 + 10 = 15 = 0Fh olur. 0000 1111b'de dört adet 1 biti vardır; dört çift sayı olduğundan PF = 1'dir. Adım 5'te AL = 15 − 8 = 7 = 07h olur. Ödünç gerekmediği için CF = 0 kalır. 0000 0111b'de üç adet 1 vardır ve PF = 0 olur.

4.1.8.10Sayı yazımı

Tablo 4.1.28 emu8086 ve MASM uyumlu assembler'larda sabitlerin yazım kurallarını özetler. Bütün örneklerin onluk değeri 25'tir; yalnız 0FFh ve karakter satırı farklıdır.

Tablo 4.1.28: Sayı tabanları ve sonekleri.
TabanSonekÖrnekOnluk değer
Onluk (decimal)yok ya da d25, 25d25
İkili (binary)b00011001b25
Sekizli (octal)o ya da q31o25
Onaltılık (hexadecimal)h19h, 0FFh25, 255
Karakter' ''A'65 (41h)

Onaltılık bir sayı A–F harflerinden biriyle başlıyorsa önüne 0 eklenir: 0Ah, 0B800h. Bu kural assembler'ın sayı ile adı ayırt edebilmesi içindir. Ah yazılırsa AH yazmacıyla, B800h yazılırsa bir etiket ya da değişken adıyla karışır. Assembler her adın bir harfle, her sayının bir rakamla başladığını varsayar. emu8086 ayrıca C dilindeki 0x1000 biçimini de kabul eder. Sekizli sayılar için o harfi sıfıra benzediğinden bazı programcılar q'yu tercih eder.

Örnek 4.1.4

200 sayısı ikili, sekizli ve onaltılık olarak nasıl yazılır? MOV AL, 200 ile MOV AL, 0C8h aynı makine kodunu üretir mi?

200 = 128 + 64 + 8 olduğundan ikili 11001000b'dir. Üçer bitlik gruplarla 11 001 000 = 3 1 0, yani 310o; dörder bitlik gruplarla 1100 1000 = C 8, yani 0C8h. C harfle başladığı için önüne 0 konmuştur. İki komut da B0 C8 üretir; taban yalnız kaynak kodun okunuşunu değiştirir.

4.1.9Sık yapılan hatalar

Bellek erişimindeki hataların çoğu derleme hatası vermez. Program çalışır, ama yanlış adresten okur ya da yanlış baytı bozar. Bu hatalar emu8086'da bellek penceresinde etkin adres ve fiziksel adres denetlenerek bulunur. Tablo 4.1.29 en sık rastlananları toplar.

Tablo 4.1.29: Bellek erişiminde sık yapılan hatalar.
HatalıNe olur?Doğrusu
MOV SI, diziSI'ya dizinin adresi değil ilk elemanın değeri yüklenir.MOV SI, OFFSET dizi ya da LEA SI, dizi
INC SI (sözcük dizisi)Sözcüğün ortasından okunur; iki elemanın yarıları birleşir.ADD SI, 2
MOV AL, [BP] ile değişkenSS kesiminden okunur; EXE programında yanlış bayt gelir.[BX], [SI] ya da DS:[BP]
MOV [BX], 5Boyut belirsiz; assembler hata verir ya da tahmin eder.MOV BYTE PTR [BX], 5
MOV AX, B800hB800h bir etiket adı sanılır.MOV AX, 0B800h
DS'yi değiştirip bırakmakSonraki bütün değişken erişimleri başka kesime gider.PUSH DS … POP DS ya da ES
MOV AX, [0200h] → 3412h beklemekLittle-endian unutulmuştur: bellekte 34 12 varsa AX = 1234h.düşük adres = düşük bayt

İlk satır assembler'ın söz dizimine bağlıdır. MASM ve emu8086'da veri tanımlı bir ad, bir değişken olarak işlenir. MOV SI, dizi yazımı MOV SI, [dizi] ile aynı anlama gelir ve dizinin ilk sözcüğünü okur. SI bundan sonra ilgisiz bir yeri gösterir. Adres için OFFSET işleci ya da LEA (etkin adresi yükle) komutu kullanılır. NASM gibi bazı assembler'larda ise yalın ad her zaman adres demektir ve içerik için köşeli parantez zorunludur. Bir kaynak koddan diğerine geçerken bu fark gözden kaçırılmamalıdır.

Sık yapılan hata

Fiziksel adresi hesaplarken kesimi kaydırmayı unutmak. DS = 2000h, BX = 0150h için fiziksel adres 20000h + 0150h = 20150h'dir; 2000h + 0150h = 2150h değildir. Ters hatada bağıl konum kaydırılır: 2000h + 1500h = 3500h. Kesim her zaman sağına bir 0 eklenerek yazılır, bağıl konum olduğu gibi kalır.

Sık yapılan hata

Etkin adres taşmasını 20 bite taşımak. BP = FFFEh iken [BP+4] için EA 1 0002h değil, 0002h'dir. Etkin adres her zaman 16 bitte sarar; taşan bit kesim değerine eklenmez. Kesim:bağıl konum toplamı ise 20 bitte sarar.

4.1.10Alıştırmalar ve çözümleri

Sunumdaki altı alıştırma burada ara adımlarıyla çözülmüştür.

1. DS = 3000h, BX = 0010h, SI = 0005h için [BX+SI+20h] işleneninin etkin ve fiziksel adresi nedir?

Adreste BP yoktur, kesim DS'dir. EA = 0010h + 0005h + 0020h = 0035h. Fiziksel adres 3000h × 10h + 0035h = 30000h + 0035h = 30035h'dir.

2. SS = 4000h, BP = FFFEh için [BP+4] işleneninin etkin ve fiziksel adresi nedir?

EA = FFFEh + 0004h = 1 0002h; 16 bitte sarar ve EA = 0002h olur. BP olduğundan kesim SS'dir: 40000h + 0002h = 40002h.

3. [BX+BP], [DI+SI], [BX+DI+300], [DX] yazımlarından hangileri geçerlidir?

Yalnız [BX+DI+300] geçerlidir: bir taban, bir indis ve bir d16. [BX+BP] iki taban, [DI+SI] iki indis yazmacı içerir. DX adres hesabında hiç kullanılamaz.

4. [0500h] = 78h, [0501h] = 56h ise MOV AX, [0500h] sonrası AX nedir? MOV AL, [0501h] sonrası AL nedir?

Sözcük okumada düşük adres düşük bayttır: AL = 78h, AH = 56h, AX = 5678h. İkinci komut yalnız 0501h'deki baytı okur: AL = 56h.

5. Ekranın 10. satır, 40. sütun konumuna yeşil zemin üzerine sarı 'X' yazan kod nasıl olur? Renk baytı 2Eh'dir.

Çözüm Örnek 4.1.3'te ayrıntılı verilmiştir. Bağıl adres (10 × 80 + 40) × 2 = 1680 = 690h'dir; yazılacak sözcük 2E58h'dir.

MOV AX, 0B800h
MOV DS, AX
MOV BX, 690h
MOV WORD PTR [BX], 2E58h

6. Ekrana 'A' yazan program DS'yi değiştirmeden ES ile nasıl yazılır?

B800h, DS yerine ES'ye yüklenir ve yazma komutuna ES: öneki eklenir. DS programın kesiminde (0700h) kalır.

MOV AX, 0B800h
MOV ES, AX
MOV CL, 'A'
MOV CH, 11011111b
MOV BX, 15Eh
MOV ES:[BX], CX      ; 26 89 0F

Yazma komutunun makine kodu, öneksiz hâlinin (89 0F) önüne 26 eklenmiş biçimidir. Program sonunda B815Eh = 41h, B815Fh = DFh olur ve DS = 0700h kalır.

4.1.11Özet

  • Adresleme: bir bellek işleneni [taban + indis + yer değiştirme] biçimindedir. Taban BX ya da BP, indis SI ya da DI, yer değiştirme d8 ya da d16'dır; her biri isteğe bağlıdır. BX ile BP, SI ile DI bir arada kullanılamaz. Bu kurallar 24 birleşim verir ve ModR/M baytının MOD ile R/M alanlarında kodlanır.
  • Mod türleri: anlık ve yazmaç modları belleğe gitmez. Doğrudan, yazmaç dolaylı, tabanlı, indisli ve tabanlı-indisli modlar bir etkin adres hesaplar. Dizgi komutları DS:SI ve ES:DI'yi örtük kullanır; G/Ç komutları ayrı bir port alanına, atlamalar IP'ye göre göreceli adrese gider.
  • Etkin adres 16 bitte hesaplanır ve sarar: BP = FFFEh iken [BP+4] → 0002h. d8 işaret genişletilir. EA hesabı 8086'da 5–12 saat turu sürer; kesim öneki 2 tur ekler.
  • Kesim seçimi: adreste BP varsa SS, yoksa DS. Kesim öneki (ES: = 26h, CS: = 2Eh, SS: = 36h, DS: = 3Eh) bunu tek komut için değiştirir. CS:IP, SS:SP ve dizgi hedefi ES:DI değiştirilemez.
  • Fiziksel adres = kesim × 10h + EA; 1234:7890 → 19BD0h. Bir fiziksel adrese en çok 4096 kesim:bağıl konum çifti gider. n adres hattı 2n konum seçer; 8086'nın 20 hattı 1 MB, 16 bitlik bağıl konum 64 KB'lık kesim verir.
  • Boyut: byte ptr / word ptr (emu8086'da b. / w.) erişim boyutunu belirtir; diğer işlenen yazmaçsa boyut ondan anlaşılır. 8086 little-endian'dır: düşük bayt düşük adrese. Sözcük dizisinde bayt uzaklığı indis × 2'dir.
  • MOV kopyalar ve bayrakları etkilemez. Bellekten belleğe, sabitten kesim yazmacına, kesimden kesime MOV yoktur; CS ve IP hedef olamaz.
  • XCHG iki işleneni tek komutta takas eder; kesim yazmacı, sabit ve iki bellek işleneni kullanılamaz. Bayrakları etkilemez.
  • Video belleği B800h kesimindedir. Her hücre karakter + öznitelik baytıdır; bağıl adres = (satır × 80 + sütun) × 2.

4.1.12Kavram listesi

Terimlerin İngilizce karşılıkları ve öteki bölümlerdeki kullanımları terim sözlüğünde bulunur.

4.1.13Kendini Dene

  1. ES = 5000h ve DI = FFF0h iken MOV AL, ES:[DI+20h] komutu hangi fiziksel adresten okur?

    Cevap

    EA = FFF0h + 0020h = 1 0010h; 16 bitte sarar ve EA = 0010h olur. Önek ES'yi seçer: 50000h + 0010h = 50010h. Sarma olmasaydı 60010h bulunurdu; bu adres ES kesiminin dışındadır.

  2. MOV AL, [BP+SI+5] komutu kaç bayttır ve hangi kesime erişir? ModR/M baytı nedir?

    Cevap

    Kesim SS'dir, çünkü adreste BP vardır. Yer değiştirme 5, −128…127 aralığında olduğundan d8 seçilir: MOD = 01. REG = 000 (AL), R/M = 010 ([BP+SI]). ModR/M = 01 000 010 = 42h. Komut 8A 42 05, yani 3 bayttır.

  3. DS:0300h'den başlayarak bellekte 78 56 34 12 baytları var. MOV AX, [0301h] ve MOV BL, [0303h] sonrası AX ve BL nedir? Birinci komutta veri yolu açısından ne olur?

    Cevap

    AX: 0301h'deki 56h AL'ye, 0302h'deki 34h AH'ye gelir; AX = 3456h. BL = 12h. 0301h tek bir adrestir. 8086 tek adresten başlayan sözcüğü iki ayrı yol döngüsüyle okur; sonuç aynıdır ama erişim 4 saat turu uzar.

  4. Aşağıdaki program bitince AX nedir?

    org 100h
    mov bx, offset t
    mov si, 3
    mov al, [bx+si]
    mov ah, [bx+si-2]
    ret
    t db 10h,20h,30h,40h,50h
    Cevap

    [bx+si] t'nin 3 numaralı baytıdır (0'dan sayılarak): AL = 40h. [bx+si-2] 1 numaralı bayttır: AH = 20h. AX = 2040h. Programın uzunluğu 12 bayt olduğundan t 010Ch'dedir; sonuç bu adresten bağımsızdır.

  5. 45678h fiziksel adresine DS:SI ile ulaşmak isteniyor. DS en küçük ve en büyük kaç olabilir? Kaç farklı çift vardır?

    Cevap

    En büyük DS: ilk dört basamak, 4567h; SI = 45678h − 45670h = 0008h. En küçük DS: DS × 10h ≥ 45678h − FFFFh = 35679h, yani DS ≥ 3567,9h → 3568h; SI = 45678h − 35680h = FFF8h. Çift sayısı 4567h − 3568h + 1 = 1000h = 4096.

  6. 18 adres hattı ve 8 veri hattı olan bir bellek yongasının kapasitesi nedir? 18 adres ve 4 veri hattı olsaydı?

    Cevap

    218 = 262 144 konum; her konum 1 bayt → 256 KB. 4 veri hattıyla her konum 4 bittir: 262 144 × 4 bit = 1 048 576 bit = 128 KB.

  7. Aşağıdakilerden hangileri 8086 assembler'ında kabul edilir? MOV ES, [BX] · MOV [SI], DS · MOV AX, [DX] · XCHG [SI], [DI] · MOV BYTE PTR [DI], 300

    Cevap

    İlk ikisi geçerlidir: kesim yazmacı bellekten yüklenebilir (8E 07) ve belleğe yazılabilir (8C 1C). [DX] geçersizdir; DX adres yazmacı değildir. XCHG iki bellek işleneni alamaz. 300 bir bayta sığmaz (en çok 255); assembler hata verir.

  8. 80 × 25 metin ekranının en son hücresinin (satır 24, sütun 79) video belleğindeki bağıl adresi nedir? Bu hücrenin renk baytı hangi fiziksel adrestedir?

    Cevap

    (24 × 80 + 79) × 2 = 1999 × 2 = 3998 = 0F9Eh. Karakter B8000h + 0F9Eh = B8F9Eh'de, renk baytı bir sonraki adreste, B8F9Fh'dedir. Ekranın tamamı 4000 bayt olduğundan son bayt 0F9Fh'dir.

  9. MOV AX, [BX+SI+6] ile MOV AX, [BX+DI+6] komutları 8086'da kaçar saat turu sürer? EA tek bir adres çıkarsa ne değişir?

    Cevap

    Bellekten yazmaca MOV 8 tur artı EA süresidir. [BX+SI+d] için EA 11, [BX+DI+d] için 12 turdur: 19 ve 20 tur. EA tek ise sözcük iki yol döngüsünde okunur ve süreye 4 tur eklenir: 23 ve 24 tur.

4.1.14İleri okuma

  • B. B. Brey, The Intel Microprocessors (8. baskı), Bölüm 3 (Addressing Modes): veri, program ve yığın adresleme modları, 8086'dan Pentium'a kadar örneklerle; bu notun adresleme kısmına en yakın kaynaktır.
  • Intel, 8086/8088 User's Manual: Programmer's and Hardware Reference: ModR/M kodlaması, kesim öneki ve komut süre tablosu (EA süreleri dahil) birinci elden buradadır.
  • K. R. Irvine, Assembly Language for x86 Processors (7. baskı), Bölüm 4: veri aktarımı, little-endian, OFFSET, PTR ve dolaylı adresleme; gerçek mod örnekleri.
  • emu8086 belgeleri, 8086 assembler tutorial for beginners, Part 2: Memory Access ve MOV instruction; sunumdaki MOV örneklerinin kaynağıdır.

4.1.15Kaynaklar

  1. emu8086 belgeleri, 8086 assembler tutorial for beginners, bölüm 2: memory access, MOV instruction.
  2. Intel, 8086/8088 User's Manual, adresleme modları ve komut kodlaması.
  3. B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, bölüm 3 (Addressing Modes).
  4. IBM PC metin modu video belleği (B800h) ve öznitelik baytı belgeleri.
  5. K. R. Irvine, Assembly Language for x86 Processors, 7. baskı, Pearson.

İlgili sayfalar: Bölüm 4.1 sunumu · Çalışma soruları · Terim sözlüğü · © Sercan Külcü. Tüm hakları saklıdır.