ADRESLEME MODLARI Bildiğiniz gibi programları oluşturan kodlar ve veriler hafızaya yüklendikten sonra işlemci tarafından satırsatır icra edilirler. Ayrıca CPU tüm giriş çıkış işlemlerini de hafızaya erişerek yapar. Bilgisayarın donanım ve yazılım düzeyinde yaptığı bunca çeşitli iş için CPU hafızaya değişik yollardan erişme ihtiyacı duyar. Sizlerde programlarınızı yazarken CPU nun hafızaya nasıl erişeceğini yazdığınız kodlarla belirtmek zorundasınız. Assembly dilinin ilk basamağı olan adresleme modları da bu konuları ele alıyor. Her mikroişlemci üreticisi bir mikro işlemci piyasaya sürdüğünde, komut setini ve adresleme modlarını da yayınlar.
Programcılar da bu belgelere göre programlarını yazarlar. Intel 8086 işlemcisini piyasaya sürdüğünde oldukça kullanışlı bir dizi adresleme modu sağladı. Intel in şu ana kadar ürettiği işlemcilerde bu adresleme modlarını kullanabilirsiniz. Daha sonraları bir devrim niteliğinde olan 80386 işlemcisi ile ek adresleme modlarıda geldi. Bu özel adresleme modları sadece 386 ve sonrası işlemcilerde kullanılabilir. Bu ek adresleme modları ile assembly programlama dili daha esnek bir yapıya büründü. Bizde adresleme modlarını 386 öncesi ve sonrası olarak ikiye ayıracağız.
Şu ana kadar yaptığımız programlarda çok fazla komut örneği görmedik ama MOV komutunu fazla kullandık ve biraz tanıdık. MOV komutu assembly programlama dilinde en çok kullanılan komutların başında gelir. Çünkü bir program çalışırken genelde hafızaya yazar yada okur. MOV komutu da bu iş için biçilmiş kaftandır ve bu kadar çok kullanıldığından dolayı bir çok adresleme modunu destekler, yani bu komut ile hafızaya çok değişik yollardan erişebilirsiniz. Bu yüzden adresleme modlarını işlerken MOV komutunu örnek alacağız. MOV komutunun genel kullanım şekli; MOV hedef, kaynak
8086 ADRESLEME MODLARI: 8086 Kaydedici Adresleme: Adından anlaşılacağı gibi kaydediciden kaydediciye yapılan işlemlerde bu adresleme modları kullanılır. En hızlı adresleme modu dur, çünkü işlem hafızada değil işlemcinin içinde gerçekleşir. Genel amaçlı ve indeks kaydedicilerde kaydedici adresleme modları: mov ax, bx ; BX teki değeri AX e kopyalar mov dl, al ; AL teki değeri DL ye kopyalar mov si, dx ; DX teki değeri SI ya kopyalar mov sp, bp ; BP deki değeri SP ye kopyalar mov dh, cl ; CL deki değeri DH a kopyalar mov ax, ax ; Bu da doğru bir kullanımdır! Kaydedici adreslemede en çok dikkat etmeniz gereken husus hedef ve kaynağın boyutlarıdır. Örneğin 16 bitlik bir kaydediciden 8 bitlik bir kaydediciye taşıma yapılamaz! mov al, bx ;yanlış kullanım, derleme anında assembler hata verir. Küçük boyuttaki kaynaktan büyük boyuttaki hedefe de kopyalama yapılamaz. mov cx, al ; Yanlış kullanım, AL ile CX eşit boyutta değil.
Bunlara ek olarak segment kaydedicilerinin kullanımında dikkat edilmesi gereken noktalar vardır. 1- Segment kaydedicileri arasında bir transfer işlemi ancak genel amaçlı bir kaydedici vasıtasıyla yapılabilir. mov ds,cs ; Bu kodlama doğru kullanılmayan segment kaydedicisi şeklinde assembler hata verir! Bu işi yapmak için, mov mov ax,cs ds,ax komut satırları kullanılabilir. 2- CS ve IP kaydedicilerinin değeri kaydedici adresleme ile değiştirilemez mov cs, ax ; kaynak genel amaçlı kaydedici olmasına rağmen bu işlem mümkün değildir! Segment kaydedicileri programın icrası aşamasında hafızanın segment olarak adlandırılan bölümlerinin adreslerini tuttuklarından, bu kaydediciler veri saklamak veya taşımak için kullanılmamalıdırlar. Bunun yerine genel amaçlı kaydedicilerin kullanılması daha uygundur.
8086 Hafıza Adresleme Modları a- Acil Adresleme (Immediate Addressing) Herhangi bir genel amaçlı veya indeks kaydedicisine doğrudan bir değer yükleyebilirsiniz. Yüklenecek olan veri kod segmentten alınacağından bu tür kullanımdan kaçınılmalıdır. İyi bir program organizasyonu için, veriler hafızanın ayrı bir bölümünde (mesela data segmentte) değişkenler veya sabitler olarak belirtilmelidir. mov al, 17 ; AL ye 17h yüklenir. b- Direkt Adresleme (Displacement Only Addressing) Acil adreslemenin doğru kullanılmış şeklidir. Bu adreslemede segment:ofset adresi kullanılarak hafızaya erişilir. mov al, ds:12 ; ds:000c adresinden 1 byte AL ye kopyalanır. mov ds:12, al ; AL nin içeriği ds:000c adresine kopyalanır. mov ax, ds:12 ; ds:000c adresinden 2 byte AX ye kopyalanır. mov ds:12, ax ; AX nin içeriği ds:000c adresinden itibaren kopyalanır (2 byte) Aslında kaynak kod hazırlanırken genelde bu şekilde bir kod yazımı yapılmaz. Değişkenler ve sabitler sembolik kelimelerle ifade edildiğinden buna gerek yoktur. Ne var ki debugger programlarında da sembolik değişken isimlerini değil adresleri görürüz. Aşağıdaki kod parçasını inceleyin;.data sayi db 5.code mov mov ax, @data ds, ax mov al, sayi ; 5 değerini al ye yükler. mov al, ds:0000 ; aynı işi yapar yani 5 i AL ye yükler. ; veriler tanımlanırken sayi db 5 şeklinde değil de ; sadece db 5 yazılsaydı, bu komutu kullanmak zorunda kalırdık.
c-kaydediciye Dayalı Dolaylı Adresleme (Register Indirect Addressing) Burada operand olarak kullanılan kaydedici köşeli parantez içine alınır ve bu andan itibaren bir offset adresini gösterir. mov al, [bx] ; hafızadan AL ye 1 byte taşınır. Alınacak verinin offset adresi BX in değeridir. mov al, [bx] mov al, [si] mov al, [di] mov al, [bp] Yukarıdaki 4 örnekte AL ye kopyalanacak verilerin offset adresleri ilgili kaydedicinin içindeki değerdir. Segment adresleri ise ilk dördünün DS sonuncusunun SS dir. BP indeks kaydedicisi yalnız başına hafıza adreslemede kullanılırsa, daima stack segmentin (SS) offset adreslerini gösterir. Fakat BP kaydedicisi de dahil olmak üzere bu adresleme segment kaydedicileri de belirtilerek yapılırsa, o zaman ilgili segment:offset adresine erişilmiş olunur. BX=0000, BP=0001, SI=0002, DI=0003 olduğunu varsayalım; mov al, cs:[bx] ; AL ye CS:0000 dan kopyalama yapılır mov al, [bx] ; AL ye DS:0000 dan kopyalama yapılır mov al, ds:[bp] ; AL ye DS:0001 den kopyalama yapılır mov al, [bp] ; AL ye SS:0001 den kopyalama yapılır mov al, ss:[si] ; AL ye SS:0002 den kopyalama yapılır mov al, [si] ; AL ye DS:0002 den kopyalama yapılır mov al, es:[di] ; AL ye ES:0003 den kopyalama yapılır mov al, [di] ; AL ye DS:0003 dan kopyalama yapılır
d- İndeksli adresleme (Indexed Addressing) Kaydedici dolaylı adreslemenin operandına sabit bir değer eklenmiş halidir. Kullanım şekli; mov al, disp[bx] mov al, disp[bp] mov al, disp[si] mov al, disp[di] Not : disp kısaltması İngilizcede displacement kelimesinin karşılığıdır. Buradaki anlamı ise referans alınan ofset adresidir. Komut setlerinde adresleme modları açıklanırken disp veya mem kısaltmaları kullanılacaktır. Mesela BX=2000h olsun, mov dl, 20h[bx] şeklinde bir komut kullanıldığında, DS:2020h adresindeki 1 byte lık değer dl ye kopyalanacaktır. Aynı şekilde BP=3030h olduğunu varsayalım, mov dh,1020h[bp] gibi bir komut ile, SS:4050h adresindeki 1 byte lık değer dh a kopyalanır. Bu adresleme modunda da BP segment kaydedicisi daima SS in ofsetlerini gösterir. Fakat kaydedici dolaylı adreslemede de olduğu gibi bizzat segment kaydedicisinide belirterek bu adresleme modunu kullanabiliriz. Bu durumda ofset adresleri komutta belirtilen segmentin ofseti olur. mov al, ss:disp[bx] ; BX normalde DS nin ofsetlerini gösterirken burada SS in ofseti olmuş. mov al, es:disp[bp] ; BP normalde SS nin ofsetlerini gösterirken burada ES in ofseti olmuş. mov al, cs:disp[si] ; SI normalde DS nin ofsetlerini gösterirken burada CS in ofseti olmuş. mov al, ss:disp[di] ; DI normalde DS nin ofsetlerini gösterirken burada SS in ofseti olmuş.
e- Taban İndeksli adresleme ( Based Indexed Addressing ) Bu adresleme modu da kaydedici dolaylı adreslemeye çok benzer. Kullanım formatı aşağıdaki gibidir; mov al, [bx][si] mov al, [bx][di] mov al, [bp][si] mov al, [bp][di] BX in 0500h SI nın 0360h olduğunu varsayalım, mov al,[bx][si] gibi bir komut işlenince AL ye kopyalanacak veri DS:0860 adresinden alınır. Aynı şekilde; BP=1598h DI=1004 ve mov ax,[bp+di] gibi bir komut işleniyorsa; AX, SS:259Ch ve SS:259Dh adreslerindeki veri ile yüklenir. SI ve DI kaydedicileri için Intel in özel komutları vardır, bu yüzden bu kaydediciler genellikle programlamada indeks değerlerini tutar, arttırır veya azaltırlar f- Taban İndeksli artı direkt adresleme (Based Indexed Plus Displacement Addressing) Bu adresleme modu taban indeksli adreslemeye 8 yada 16 bitlik sabit bir değerin eklenmiş halidir. mov al, disp[bx][si] mov al, disp[bx+di] mov al, [bp+si+disp] mov al, [bp][di][disp] BP = 1000h, BX= 2000h, SI= 0120h, DI = 5 olduğunu varsayalım. mov al,10h[bx+si] ; AL ye DS:2130 adresindeki veri yüklenir mov ch,125h[bp+di] ; CH a SS:112A adresindeki veri yüklenir mov bx,cs:2[bx][di] ; CS:2007 adresinden itibaten 2 byte lık veri yüklenir.
TASM ve MASM ın adresleme modları için esnekliği. TASM ve MASM assembler ları indeksli, taban indeksli, ve taban indeksli artı direkt adresleme için değişik yazım şekillerini desteklerler; İndeksli adresleme için; disp[bx] = [bx][disp] = [bx+disp] = [disp][bx] = [disp+bx] Taban indeksli adresleme için; [bx][si] = [bx+si] = [si][bx] = [si+bx] ; Taban İndeksli artı direkt adresleme için; disp[bx][si] = disp[bx+si] = [disp+bx+si] = [disp+bx][si] = disp[si][bx] = [disp+si][bx] = [disp+si+bx] = [si+disp+bx] = [bx+disp+si] Yukarıda yazılan bu 3 adresleme modundaki operandlar aynı işi yaparlar. MASM ve TASM "[ ]" sembollerine "+" operatörü gibi davranır. ( disp[bx][si] = disp[bx+si] örneğinde olduğu gibi )
8086 Adresleme Hafıza Adresleme Modlarını Hatırlamak İçin Kolay Bir Yol: 8086 işlemcisi için toplam 17 adet adresleme modu mevcuttur. Bunlar disp, [bx], [bp], [si], [di], disp[bx], disp[bp], disp[si], disp[di], [bx][si], [bx][di], [bp][si], [bp][di], disp[bx][si], disp [bx][di], disp[bp][si], and disp[bp][di] adresleme modlarıdır. Yandaki şekil, bu 17 adresleme modunu ezberlemeniz yerine kolayca hatırlamanıza yardımcı olacaktır. Bir tek eleman seçin; disp, [bx], [bp], [si], [di] 3. sütunu yok sayın ve diğer elemanların birleşimini çıkartın disp[bx], disp[bp] 2. sütunu yok sayın ve diğer elemanların birleşimini çıkartın disp[si], disp[di] 1. sütunu yok sayın ve diğer elemanların birleşimini çıkartın [bx][si], [bx][di], [bp][si], [bp][di] Son olarak tüm sütunların birleşimi ile aşağıdaki geçerli adresleme modlarını kolayca çıkartabilirsiniz. disp[bx][si], disp [bx][di], disp[bp][si], disp[bp][di].
4 1 5 2 3 Turbo Debugger ekranı 5 bölümden oluşuyor. Şekildeki 1, 2 ve 3 nolu kısımlar hafızayı incelemek için kullanılırlar. 4. kısım mikroişlemci kaydedicilerini ve 5. kısımdada yine mikroişlemci kaydedicilerinden olan flag register ı bitsel olarak görebilirsiniz. Genellikle 1. bölge programı oluşturan kodları, 2. bölgede verilerin incelenmesi için kullanılır. 3. bölgeyi yığın hafızayı gözlemlemek için kullanabilirsiniz.
Turbo Debugger açıldıktan sonra "File" menüsünden derlediğiniz program dosyasını açıp kodlarını inceleyebilirsiniz. Program dosyanızı açtıktan sonra "Program has no symbol table" diye bir mesaj gelebilir. Bu mesaj penceresinde "OK" e tıklayıp çalışmaya başlayabilirsiniz.
Ayrıca menülerden sırasıyla View/Another/File seçeneklerini tıklayarak başka bir dosyayı diğer bir pencerede açabilirsiniz. (Mesela kaynak dosyasını) Eğer bu pencerede yazı yerine hex kodları görürseniz, pencerenin üzerine sağ tıklayıp açılan menüden "Display As" ı seçin.
Programı çalıştırma seçeneklerini "Run" menüsünden seçebilirsiniz. F8 tuşu programı adım adım işletmek için kullanılır, F7 ise adım-adım program işlenirken döngüleri incelemenizi sağlar. Program adım-adım işlenirken mavi bir çubuk o anda hangi komutun işleneceğini gösterir. Aynı ekranda işlemcinin kaydedicilerinin nasıl değiştiğini gözlemleyebilirsiniz. Değişikliğe uğrayan kaydediciler beyaz görünür. Programın tekrar çalıştırmak için "Run" menüsünden "Program Reset" seçeneğini seçebilirsiniz. Verilerinizi görmek için 2. pencereye sağ tıklayıp "goto" yu seçin. Açılan pencereye görmek istediğiniz adresi yazın.
Programınız satır-satır işlenme sürecinde, adresleme yapılan bir komutun işlenmesi anında kod penceresinin sağ üst köşesinde hafızanın hangi bölgesine erişildiği görülebilir. Kaynak csharpnedir.com