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.
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.
| 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.
| Komut | Makine kodu | MOD | R/M | Uzunluk |
|---|---|---|---|---|
MOV AL, [BX+SI] | 8A 00 | 00 | 000 | 2 bayt |
MOV AL, [BX+DI] | 8A 01 | 00 | 001 | 2 bayt |
MOV AL, [BP+SI] | 8A 02 | 00 | 010 | 2 bayt |
MOV AL, [BP+DI] | 8A 03 | 00 | 011 | 2 bayt |
MOV AL, [SI] | 8A 04 | 00 | 100 | 2 bayt |
MOV AL, [DI] | 8A 05 | 00 | 101 | 2 bayt |
MOV CL, [1234h] | 8A 0E 34 12 | 00 | 110 | 4 bayt |
MOV AL, [BX] | 8A 07 | 00 | 111 | 2 bayt |
MOV AL, [BP] | 8A 46 00 | 01 | 110 | 3 bayt |
MOV AL, [BX+5] | 8A 47 05 | 01 | 111 | 3 bayt |
MOV AL, [BX+128] | 8A 87 80 00 | 10 | 111 | 4 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.
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 kodu8A 41 FC'dir. BuradaFC, −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.
İş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.
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.
| Yazım | Durum | Açıklama |
|---|---|---|
[BX] | geçerli | yazmaç dolaylı, DS |
[1234h] | geçerli | doğrudan adres, DS |
[SI+10] | geçerli | indisli, d8, DS |
[BP+DI-2] | geçerli | tabanlı-indisli, d8, SS |
ES:[BX+SI] | geçerli | kesim önekli, ES |
[AX], [CX], [DX] | geçersiz | bu yazmaçlar adres hesabında kullanılamaz |
[BL], [BH] | geçersiz | 8 bitlik yazmaç 16 bitlik bağıl konum tutamaz |
[BX+BP] | geçersiz | iki taban yazmacı |
[SI+DI] | geçersiz | iki indis yazmacı |
[SP], [BX*2] | geçersiz | 8086'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.
İ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.
| Mod | Örnek | İşlenen nerede? |
|---|---|---|
| Anlık (immediate) | MOV AX, 5 | komutun içinde (sabit) |
| Yazmaç (register) | MOV AX, BX | yazmaç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ı-indisli | MOV AL, [BX+DI] | DS:BX+DI |
| Tabanlı-indisli + yer değiştirme | MOV 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.
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 ilerlerG/Ç 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 yazGö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 − 6Baş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,66hORG 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.
| Komut | Makine kodu | Mod | EA | Fiziksel | Sonuç |
|---|---|---|---|---|---|
MOV AH, 7 | B4 07 | anlık | — | — | AH = 07h |
MOV AL, [tablo+1] | A0 17 01 | doğrudan | 0117h | 07117h | AL = 22h, AX = 0722h |
MOV CL, [BX] | 8A 0F | yazmaç dolaylı | 0116h | 07116h | CL = 11h |
MOV CH, [BX+4] | 8A 6F 04 | tabanlı | 011Ah | 0711Ah | CH = 55h, CX = 5511h |
MOV DL, [BX+SI] | 8A 10 | tabanlı-indisli | 0118h | 07118h | DL = 33h |
MOV DH, [BX+SI+3] | 8A 70 03 | tabanlı-indisli + d8 | 011Bh | 0711Bh | DH = 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.
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- Taban yazmacı BX = 0200h alınır.
- İndis yazmacı SI = 0030h eklenir: 0230h.
- 8 bitlik yer değiştirme +4 eklenir.
- EA = 0200h + 0030h + 0004h = 0234h. Toplama 16 bitliktir; burada taşma yoktur.
- Adreste BP olmadığından kesim DS'dir. Fiziksel adres = 1000h × 10h + 0234h = 10000h + 0234h = 10234h. AL, bu adresteki baytı alır.
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- Taban yazmacı BP = 0100h alınır.
- İndis yazmacı DI = 0010h eklenir: 0110h.
- Yer değiştirme −2'dir; makine kodunda
FEbaytı olarak durur ve işaret genişletmeyle FFFEh olur. - EA = 0100h + 0010h + FFFEh = 1 010Eh → 010Eh. Taşan bit atılır; sonuç 0110h − 2 ile aynıdır.
- 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].
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.
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.
| Erişilen veri | Uygun mod | Örnek |
|---|---|---|
| Tek bir değişken | doğrudan | MOV AX, sayac |
| İşaretçinin gösterdiği eleman | yazmaç dolaylı | MOV AL, [SI] |
| Dizinin i. elemanı (dizi sabit, indis değişken) | indisli + d16 | MOV AL, dizi[SI] |
| Bir kaydın (yapının) alanı | tabanlı + d8 | MOV AX, [BX+2] |
| Matris ya da kayıt dizisi | taban + indis + d | MOV AL, mat[BX+SI] |
| Yığındaki parametre ya da yerel değişken | tabanlı, BP ile (SS) | MOV AX, [BP+4] |
| Başka kesimdeki tampon | kesim önekli | MOV 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,34hMatris 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.
| Adım | Komut | BX | SI | EA | AX | DL |
|---|---|---|---|---|---|---|
| 1 | mov bx, 2*4 | 0008h | 0000h | — | 0000h | 00h |
| 2 | mov si, 1 | 0008h | 0001h | — | 0000h | 00h |
| 3 | mov al, mat[bx+si] | 0008h | 0001h | 0122h | 0032h | 00h |
| 4 | mov si, 3 | 0008h | 0003h | — | 0032h | 00h |
| 5 | mov ah, mat[bx+si] | 0008h | 0003h | 0124h | 3432h | 00h |
| 6 | sub bx, 4 | 0004h | 0003h | — | 3432h | 00h |
| 7 | mov dl, mat[bx+si] | 0004h | 0003h | 0120h | 3432h | 24h |
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.
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.
| Etkin adres birleşimi | Saat turu |
|---|---|
[BX], [BP], [SI], [DI] | 5 |
doğrudan [d16] | 6 |
[BP+DI], [BX+SI] | 7 |
[BP+SI], [BX+DI] | 8 |
| tek yazmaç + d8/d16 | 9 |
[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.
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):
- Kesim ve bağıl konum alınır: 1234h ve 7890h.
- 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.
- Bağıl konum, toplamaya girmek üzere sağa yaslanır: 07890h.
- İki sayı toplanır: 12340h + 07890h = 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.
| Adres / veri hattı | Konum sayısı | Kapasite |
|---|---|---|
| 12 / 8 | 212 = 4096 | 4096 × 1 B = 4 KB |
| 16 / 4 | 216 = 64 K | 64 K × 4 bit = 256 Kbit = 32 KB |
| 16 / 8 | 64 K | 64 KB (bir kesim) |
| 20 / 8 | 1 M | 1 MB (8086) |
| 24 / 16 | 16 M | 16 M × 2 B = 32 MB |
| 32 / 8 | 4 G | 4 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).
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.
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.
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| IP | Komut | Makine kodu | Erişilen adres | Sonuç |
|---|---|---|---|---|
| 0100h | MOV AX, 0B800h | B8 00 B8 | — | AX = B800h |
| 0103h | MOV ES, AX | 8E C0 | — | ES = B800h, DS = 0700h |
| 0105h | MOV BX, 00A0h | BB A0 00 | — | BX = 00A0h |
| 0108h | MOV BYTE PTR ES:[BX], 'K' | 26 C6 07 4B | B80A0h | [B80A0h] = 4Bh |
| 010Ch | MOV BYTE PTR ES:[BX+1], 1Eh | 26 C6 47 01 1E | B80A1h | [B80A1h] = 1Eh |
| 0111h | MOV AL, [BX] | 8A 07 | 070A0h | AL = 00h |
| 0113h | MOV DL, ES:[BX] | 26 8A 17 | B80A0h | DL = 4Bh |
| 0116h | RET | C3 | yığın | IP = 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.
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 baslaProgramda üç 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.
| Komut | Makine kodu | DS | SS | Erişilen adres | Sonuç |
|---|---|---|---|---|---|
mov ax, veri | B8 10 07 | 0700h | 0711h | — | AX = 0710h |
mov ds, ax | 8E D8 | 0710h | 0711h | — | DS = 0710h |
mov bp, offset x | BD 03 00 | 0710h | 0711h | — | BP = 0003h |
mov al, [bp] | 8A 46 00 | 0710h | 0711h | SS:0003 = 07113h | AL = 00h |
mov bl, ds:[bp] | 3E 8A 5E 00 | 0710h | 0711h | DS:0003 = 07103h | BL = 44h ('D') |
mov si, offset x | BE 03 00 | 0710h | 0711h | — | SI = 0003h |
mov cl, [si] | 8A 0C | 0710h | 0711h | DS:0003 = 07103h | CL = 44h ('D') |
mov ax, 4C00h / int 21h | B8 00 4C / CD 21 | 0710h | 0711h | — | 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.
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.
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 kurulurDS. 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.
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.
byte ptr bir bayt, word ptr iki bayt okur.| Komut | Boyut nereden belli? |
|---|---|
MOV [BX], AL | AL 8 bit → bayt yazılır |
MOV [BX], AX | AX 16 bit → sözcük yazılır |
MOV [BX], 5 | belirsiz → MOV BYTE PTR [BX], 5 ya da MOV WORD PTR [BX], 5 |
MOV AL, sayi | AL 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| Adım | Komut | Makine kodu | 0200h 0201h 0202h 0203h | Yazmaç |
|---|---|---|---|---|
| 1 | MOV BX, 0200h | BB 00 02 | AA BB CC DD | BX = 0200h |
| 2 | MOV WORD PTR [BX], 1234h | C7 07 34 12 | 34 12 CC DD | — |
| 3 | MOV BYTE PTR [BX], 0FFh | C6 07 FF | FF 12 CC DD | — |
| 4 | MOV WORD PTR [BX], 0FFh | C7 07 FF 00 | FF 00 CC DD | — |
| 5 | MOV AX, [BX] | 8B 07 | FF 00 CC DD | AX = 00FFh |
| 6 | MOV CL, [BX+1] | 8A 4F 01 | FF 00 CC DD | CL = 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.
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.
Ç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.
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.
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, 9ABChKomutları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.
| Adım | Komut | SI | EA | Okunan baytlar | Sonuç |
|---|---|---|---|---|---|
| 1 | mov si, 1 | 0001h | — | — | — |
| 2 | mov ax, dizi[si] | 0001h | 0118h | 12 78 | AX = 7812h (yanlış) |
| 3 | shl si, 1 | 0002h | — | — | — |
| 4 | mov bx, dizi[si] | 0002h | 0119h | 78 56 | BX = 5678h = dizi[1] |
| 5 | mov si, 2 | 0002h | — | — | — |
| 6 | shl si, 1 | 0004h | — | — | — |
| 7 | mov cx, dizi[si] | 0004h | 011Bh | BC 9A | CX = 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.
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.
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:
- CS ve IP'ye MOV ile değer atanmaz. CS kaynak olarak okunabilir; IP hiçbir MOV'da yer almaz.
- İki işlenenin boyutu aynı olmalıdır: ikisi de bayt ya da ikisi de sözcük.
- İki işlenen birden bellek olamaz.
- Kesim yazmacına anlık değer yüklenemez ve bir kesim yazmacı diğerine doğrudan kopyalanamaz.
- MOV bayrakları etkilemez.
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.
| Genel amaçlı | Kesim yazmaçlarıyla |
|---|---|
MOV REG, memory | MOV SREG, memory |
MOV memory, REG | MOV memory, SREG |
MOV REG, REG | MOV REG, SREG |
MOV memory, immediate | MOV 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.
| No | Komut | Durum | Gerekçe ve doğrusu |
|---|---|---|---|
| 1 | MOV [BX], [SI] | geçersiz | bellekten belleğe MOV yok → MOV AL, [SI] · MOV [BX], AL |
| 2 | MOV DS, ES | geçersiz | kesimden kesime yok → MOV AX, ES · MOV DS, AX ya da PUSH ES · POP DS |
| 3 | MOV DS, 100h | geçersiz | kesime sabit atanamaz |
| 4 | MOV CS, AX | geçersiz | CS hedef olamaz (uzak JMP kullanılır); IP de yazılamaz (MOV IP, AX yerine JMP AX) |
| 5 | MOV [BX], 5 | geçersiz | boyut belirsiz → BYTE PTR / WORD PTR |
| 6 | MOV AX, CS | geçerli | CS kaynak olabilir; kodu 8C C8 |
| 7 | MOV SP, BX | geçerli | SP genel bir yazmaçtır; ama yığını başka yere taşır |
| 8 | MOV BL, DX | geçersiz | 8 ve 16 bit uyuşmaz |
| 9 | MOV AL, [SI+BP] | geçerli | [BP+SI] ile aynı; kesim SS |
| 10 | MOV 5, AX | geçersiz | hedef 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.
| Adım | Komut | SI | DI | CX | AL | hedef |
|---|---|---|---|---|---|---|
| 1 | mov si, offset kaynak | 0112h | 0000h | 0000h | 00h | .... |
| 2 | mov di, offset hedef | 0112h | 0116h | 0000h | 00h | .... |
| 3 | mov cx, 4 | 0112h | 0116h | 0004h | 00h | .... |
| 4 | mov al, [si] | 0112h | 0116h | 0004h | 41h | .... |
| 5 | mov [di], al | 0112h | 0116h | 0004h | 41h | A... |
| 6 | inc si | 0113h | 0116h | 0004h | 41h | A... |
| 7 | inc di | 0113h | 0117h | 0004h | 41h | A... |
| 8 | loop kopya | 0113h | 0117h | 0003h | 41h | A... |
| 9–13 | tur 2 | 0114h | 0118h | 0002h | 42h | AB.. |
| 14–18 | tur 3 | 0115h | 0119h | 0001h | 43h | ABC. |
| 19–23 | tur 4 | 0116h | 011Ah | 0000h | 44h | ABCD |
| 24 | ret | 0116h | 011Ah | 0000h | 44h | ABCD |
İ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.
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önProgramı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.
| Adres | Komut | Makine kodu | Açıklama |
|---|---|---|---|
| 0100h | MOV AX, 0B800h | B8 00 B8 | B8 = “AX'e anlık sözcük”; sabit little-endian |
| 0103h | MOV DS, AX | 8E D8 | 8E = kesim yazmacına; D8 = 11 011 000 (DS ← AX) |
| 0105h | MOV CL, 'A' | B1 41 | B0 + 1 (CL); 41h = 'A' |
| 0107h | MOV CH, 11011111b | B5 DF | B0 + 5 (CH) |
| 0109h | MOV BX, 15Eh | BB 5E 01 | B8 + 3 (BX) |
| 010Ch | MOV [BX], CX | 89 0F | 89 = yazmaçtan belleğe sözcük; 0F = 00 001 111 |
| 010Eh | RET | C3 | yakı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.
| Adım | Komut | AX | DS | CX | BX | [B800:015E] [015F] |
|---|---|---|---|---|---|---|
| 0 | (başlangıç) | 0000h | 0700h | 0000h | 0000h | 20h 07h |
| 1 | MOV AX, 0B800h | B800h | 0700h | 0000h | 0000h | 20h 07h |
| 2 | MOV DS, AX | B800h | B800h | 0000h | 0000h | 20h 07h |
| 3 | MOV CL, 'A' | B800h | B800h | 0041h | 0000h | 20h 07h |
| 4 | MOV CH, 11011111b | B800h | B800h | DF41h | 0000h | 20h 07h |
| 5 | MOV BX, 15Eh | B800h | B800h | DF41h | 015Eh | 20h 07h |
| 6 | MOV [BX], CX | B800h | B800h | DF41h | 015Eh | 41h DFh |
| 7 | RET | B800h | B800h | DF41h | 015Eh | 41h 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.
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.
Ö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.
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], 2E58hSon 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
RETDS: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.
| Adım | Komut | AX | IP (sonra) | [1000h] [1001h] |
|---|---|---|---|---|
| 0 | (başlangıç) | 0000h | 0100h | CD AB |
| 1 | MOV AX, [1000h] | ABCDh | 0103h | CD AB |
| 2 | RET | ABCDh | 0000h | CD 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| Adım | Komut | BX | IP (sonra) | [2000h] [2001h] |
|---|---|---|---|---|
| 0 | (başlangıç) | 0000h | 0100h | 00 00 |
| 1 | MOV BX, 1234h | 1234h | 0103h | 00 00 |
| 2 | MOV [2000h], BX | 1234h | 0107h | 34 12 |
| 3 | RET | 1234h | 0000h | 34 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.
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 ; takasSayı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.
| Adım | Komut | CX | DX |
|---|---|---|---|
| 1 | MOV CX, 10 | 000Ah | 0000h |
| 2 | MOV DX, 20 | 000Ah | 0014h |
| 3 | XCHG CX, DX | 0014h | 000Ah |
4.1.8.4XCHG kuralları
- Yazmaç ↔ yazmaç:
XCHG AX, BX. - Yazmaç ↔ bellek:
XCHG AL, [SI]. Yazım sırası önemsizdir;XCHG [SI], ALaynı 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, regbiçimi tek baytlık özel bir koda sahiptir:90h+ yazmaç numarası.XCHG AX, BX=93.XCHG AX, AXhiçbir şeyi değiştirmez ve kodu90'dır. Bu bayt aynı zamandaNOP(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 CXBu 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| Adım | Komut | AX | CX | DX | SI | sayi |
|---|---|---|---|---|---|---|
| 1 | MOV SI, OFFSET sayi | 0000h | 0000h | 0000h | 0116h | A5h |
| 2 | MOV AL, 5Ah | 005Ah | 0000h | 0000h | 0116h | A5h |
| 3 | XCHG AL, [SI] | 00A5h | 0000h | 0000h | 0116h | 5Ah |
| 4 | MOV CX, 1111h | 00A5h | 1111h | 0000h | 0116h | 5Ah |
| 5 | MOV DX, 2222h | 00A5h | 1111h | 2222h | 0116h | 5Ah |
| 6 | MOV AX, CX | 1111h | 1111h | 2222h | 0116h | 5Ah |
| 7 | MOV CX, DX | 1111h | 2222h | 2222h | 0116h | 5Ah |
| 8 | MOV DX, AX | 1111h | 2222h | 1111h | 0116h | 5Ah |
| 9 | XCHG CX, DX | 1111h | 1111h | 2222h | 0116h | 5Ah |
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.
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:3001hBu ö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.
| Adım | Komut | Makine kodu | SI | DI | AL | [3000h] [3001h] |
|---|---|---|---|---|---|---|
| 1 | MOV SI, 3000h | BE 00 30 | 3000h | 0000h | 00h | 5A ?? |
| 2 | MOV DI, SI | 8B FE | 3000h | 3000h | 00h | 5A ?? |
| 3 | MOV AL, [SI] | 8A 04 | 3000h | 3000h | 5Ah | 5A ?? |
| 4 | MOV [DI+1], AL | 88 45 01 | 3000h | 3000h | 5Ah | 5A 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
RETDS: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.
| Adım | Komut | IP (sonra) | 4000h 4001h 4002h 4003h |
|---|---|---|---|
| 0 | (başlangıç) | 0100h | 00 99 00 99 |
| 1 | MOV BYTE PTR [4000h], 65 | 0105h | 41 99 00 99 |
| 2 | MOV WORD PTR [4002h], 65 | 010Bh | 41 99 41 00 |
| 3 | RET | 0000h | 41 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 BLBirinci 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| Adım | Komut | Makine kodu | AX | CF | ZF | SF | AF | PF |
|---|---|---|---|---|---|---|---|---|
| 1 | MOV AX, 00FFh | B8 FF 00 | 00FFh | 0 | 0 | 0 | 0 | 0 |
| 2 | ADD AH, 01h | 80 C4 01 | 01FFh | 0 | 0 | 0 | 0 | 0 |
| 3 | ADD AL, 01h | 04 01 | 0100h | 1 | 1 | 0 | 1 | 1 |
| 4 | MOV AX, 01FFh | B8 FF 01 | 01FFh | 1 | 1 | 0 | 1 | 1 |
| 5 | ADD AX, 1 | 05 01 00 | 0200h | 0 | 0 | 0 | 1 | 1 |
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.
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| Adım | Komut | Makine kodu | AL | BL | CL | CF | PF |
|---|---|---|---|---|---|---|---|
| 1 | mov al, 00000101b | B0 05 | 05h | 00h | 00h | 0 | 0 |
| 2 | mov bl, 0ah | B3 0A | 05h | 0Ah | 00h | 0 | 0 |
| 3 | mov cl, 10o | B1 08 | 05h | 0Ah | 08h | 0 | 0 |
| 4 | add al, bl | 02 C3 | 0Fh | 0Ah | 08h | 0 | 1 |
| 5 | sub al, cl | 2A C1 | 07h | 0Ah | 08h | 0 | 0 |
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.
| Taban | Sonek | Örnek | Onluk değer |
|---|---|---|---|
| Onluk (decimal) | yok ya da d | 25, 25d | 25 |
| İkili (binary) | b | 00011001b | 25 |
| Sekizli (octal) | o ya da q | 31o | 25 |
| Onaltılık (hexadecimal) | h | 19h, 0FFh | 25, 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.
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.
| Hatalı | Ne olur? | Doğrusu |
|---|---|---|
MOV SI, dizi | SI'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şken | SS kesiminden okunur; EXE programında yanlış bayt gelir. | [BX], [SI] ya da DS:[BP] |
MOV [BX], 5 | Boyut belirsiz; assembler hata verir ya da tahmin eder. | MOV BYTE PTR [BX], 5 |
MOV AX, B800h | B800h bir etiket adı sanılır. | MOV AX, 0B800h |
| DS'yi değiştirip bırakmak | Sonraki bütün değişken erişimleri başka kesime gider. | PUSH DS … POP DS ya da ES |
MOV AX, [0200h] → 3412h beklemek | Little-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.
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.
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], 2E58h6. 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 0FYazma 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'dab./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.
- adresleme modu addressing mode
- anlık adresleme immediate addressing
- yazmaç adresleme register addressing
- doğrudan adresleme direct addressing
- yazmaç dolaylı adresleme register indirect addressing
- tabanlı / indisli adresleme based / indexed addressing
- göreceli adresleme relative addressing
- taban yazmacı base register
- indis yazmacı index register
- yer değiştirme displacement
- işaret genişletme sign extension
- etkin adres (EA) effective address
- ModR/M baytı ModR/M byte
- kesim segment
- bağıl konum offset
- fiziksel adres physical address
- paragraf (16 bayt) paragraph
- adres yolu address bus
- varsayılan kesim default segment
- kesim öneki segment override prefix
- PSP (program kesimi öneki) program segment prefix
- .COM programı .COM program
- veri türü belirtici data type specifier
- bayt / sözcük byte / word
- little-endian / big-endian
- satır öncelikli düzen row-major order
- takas (XCHG) exchange
- dizgi string
- G/Ç portu I/O port
- video belleği (metin modu) video memory
- öznitelik baytı attribute byte
- saat turu clock cycle
- yol döngüsü bus cycle
4.1.13Kendini Dene
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.
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. Komut8A 42 05, yani 3 bayttır.DS:0300h'den başlayarak bellekte
78 56 34 12baytları var.MOV AX, [0301h]veMOV 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.
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,50hCevap
[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.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.
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.
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], 300Cevap
İ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.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.
MOV AX, [BX+SI+6]ileMOV 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
- emu8086 belgeleri, 8086 assembler tutorial for beginners, bölüm 2: memory access, MOV instruction.
- Intel, 8086/8088 User's Manual, adresleme modları ve komut kodlaması.
- B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, bölüm 3 (Addressing Modes).
- IBM PC metin modu video belleği (B800h) ve öznitelik baytı belgeleri.
- 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.