Mikroişlemciler · Ders Notu
Bölüm 3.2: Assembly
Assembly dili, işlemcinin makine komutlarını insanın okuyabileceği kısaltmalarla yazar. Her satırı tek bir makine komutuna karşılık gelir. Bu yüzden assembly ile yazan kişi yazmaçları, belleği ve bayrakları doğrudan yönetir; derleyicinin gizlediği her ayrıntı görünür olur. Not, 8086 assembly dilini emu8086 ortamında ele alır. Önce bir satırın alanları, komut ile direktif arasındaki fark ve ad kuralları verilir. Ardından işlenen türleri, komutların yazılmayan örtük işlenenleri ve bellek erişiminin saat turu cinsinden bedeli incelenir. IP'nin her komutta nasıl ilerlediği ve bayrakları hangi komutların değiştirdiği adım adım izlenir. Son kesimlerde ilk .COM programı yazılır, belleğe yerleşen baytları tek tek okunur, emu8086 penceresinde çalıştırılır ve en sık karşılaşılan hatalar nedenleriyle birlikte sınıflandırılır.
Öğrenme çıktıları
- Assembly'nin yerini açıklamak
- Assembly dilinin makine diliyle birebir ilişkisini ve yüksek seviyeli dillerden farkını bir komutun üç görünümü üzerinden göstermek.
- Satır yapısını okumak
- Etiket, komut, işlenen ve açıklama alanlarını ayırmak; komutu direktiften ve makrodan ayırt etmek; geçerli ve geçersiz adları tanımak.
- İşlenenleri tanımak
- Yazmaç, anlık değer ve bellek işlenenlerini ve MUL, DIV, LOOP, CBW, PUSH, XLAT gibi komutların örtük işlenenlerini belirlemek.
- Komut süresini hesaplamak
- Yazmaç ve bellek işlenenli komutların süre farkını saat turu ve etkin adres hesabıyla bulmak; farkı yol döngüsüyle açıklamak.
- IP ve bayrakları izlemek
- IP'nin komut uzunluğu kadar ilerleyişini ve bayrakları değiştiren ya da değiştirmeyen komutların etkisini adım adım izlemek.
- İlk programı yazmak
- emu8086 ile bir .COM programı yazmak, baytlarını okumak, tek adımla çalıştırmak; söz dizimi hatasını mantık hatasından ayırmak.
3.2.1Assembly dili
3.2.1.1Komut kısaltmaları ve makine komutu
Bir mikroişlemci bellekten okuduğu baytları çözer ve her bayt dizisini bir işleme dönüştürür. Bu baytların oluşturduğu dile makine dili denir. Makine dili işlemcinin doğrudan anladığı tek dildir, ama insan için okunması zordur. B8 05 00 baytlarına bakan biri, bunun “AX yazmacına 5 yükle” anlamına geldiğini ancak bir tabloya bakarak çıkarabilir. Program yüzlerce komuta ulaştığında bu yöntem çalışmaz.
Assembly dili (assembly language) bu sorunu çözmek için doğdu. Her makine komutuna akılda kalan kısa bir ad verilir: taşıma için MOV, toplama için ADD, atlama için JMP. Bu kısa adlara anımsatıcı ya da komut kısaltması (mnemonic) denir. İşlenenler de sayı yerine adlarıyla yazılır: yazmaçlar AX, BX gibi; bellek konumları ise programcının verdiği adlarla.
Assembly dili, bir işlemcinin makine komutlarını anımsatıcılar ve simgesel adlarla yazan düşük seviyeli programlama dilidir. Assembly kaynağındaki her komut satırı, işlemcinin tek bir makine komutuna karşılık gelir. Bu birebir ilişki dili işlemciye bağımlı kılar: her işlemci ailesinin kendi assembly dili vardır.
Birebir ilişkiyi görmenin en kolay yolu tek bir satırı üç ayrı biçimde yazmaktır. Tablo 3.2.1 MOV AX, 5 satırının programcının, assembler'ın ve işlemcinin gözündeki hâlini yan yana verir.
| Görünüm | Yazılış | Kim kullanır? |
|---|---|---|
| Assembly | MOV AX, 5 | programcı |
| Onaltılık makine kodu | B8 05 00 | liste çıktısı, öykünücü, hata ayıklayıcı |
| İkili makine kodu | 10111000 00000101 00000000 | işlemci (veri yolundaki gerilim düzeyleri) |
Birinci bayt B8, “16 bitlik bir yazmaca anlık değer yükle” işleminin işlem kodudur (opcode). Bu komut ailesinde hedef yazmacın numarası işlem koduna eklenir. AX'in numarası 0 olduğu için kod B8h + 0 = B8h olur. BX'in numarası 3'tür; MOV BX, 3 komutunun ilk baytı bu yüzden BBh'dir. Komutun geri kalan iki baytı 16 bitlik sabiti taşır. 0005h değeri bellekte düşük bayt önce saklanır: önce 05, sonra 00. 8086'nın bu düzenine little-endian denir.
İkili satır, işlemcinin gerçekte gördüğü şeydir. 8086 komut baytlarını adres/veri hatları (AD0–AD15) üzerinden okur. Her bit bir hattaki yüksek ya da düşük gerilimdir. Bir elektronik devre gözüyle bakıldığında MOV AX, 5, komut çözücünün girişine gelen 24 bitlik bir desenden başka bir şey değildir. Çözücü bu deseni ALU'yu, yazmaç dosyasının yazma girişini ve iç yolları süren kontrol sinyallerine çevirir.
Assembly'yi yüksek seviyeli dillerden ayıran özellik de bu yakınlıktır. C'de x = a * b; yazan programcı çarpmanın hangi yazmaçta yapılacağını bilmez; bunu derleyici seçer. Assembly'de ise çarpılanın AL'de durması, sonucun AX'e yazılması, AH'deki eski değerin silinmesi programcının sorumluluğundadır. Dilin gücü de zorluğu da buradan gelir. Assembly ile yazmak, yazmaçları, belleği ve sistem yolunu bilmeyi gerektirir. Karşılığında bir programın donanımda nasıl çalıştığı bütün ayrıntısıyla görülür.
MOV BX, 1234h komutunun makine kodu nedir? Bellekte kaç bayt yer kaplar?
Komut ailesi aynıdır: 16 bitlik yazmaca anlık değer. İşlem kodu B8h + yazmaç numarası olur. BX'in numarası 3 olduğundan ilk bayt BBh'dir. Sabit 1234h, düşük bayt önce yazılır: 34h, sonra 12h. Komut BB 34 12 olarak üç bayt yer kaplar. 8 bitlik yazmaçlar için ayrı bir aile vardır: MOV AL, 5 komutu B0 05 diye iki bayta kodlanır, çünkü sabit tek bayttır.
3.2.1.2Assembler ve emu8086
Assembly kaynağı düz bir metin dosyasıdır. İşlemci bu metni çalıştıramaz; önce makine koduna çevrilmesi gerekir. Bu çeviriyi yapan programa assembler denir. Assembler komut kısaltmalarını işlem kodlarına, etiketleri adreslere, değişken adlarını da bağıl konumlara çevirir. Çeviri birebirdir: bir komut satırı bir makine komutu verir. MASM, TASM ve NASM 8086 ailesi için yaygın assembler'lardır.
Çevrilen kod bir dosyaya yazılır. Basit programlar için bu dosya doğrudan çalıştırılabilir bir .COM dosyasıdır. Çok kesimli programlar önce bir nesne dosyasına (.obj) çevrilir; ardından bağlayıcı (linker) nesne dosyalarını birleştirip bir .EXE dosyası üretir. Programı çalıştırmak için işletim sisteminin yükleyicisi dosyayı RAM'e kopyalar, kesim yazmaçlarını ayarlar ve denetimi programın ilk komutuna verir. Şekil 3.2.1 bu zinciri gösterir.
Bu derste kullanılan emu8086, zincirin bütün halkalarını tek pencerede toplar. İçinde bir metin düzenleyicisi, bir assembler ve bir 8086 öykünücüsü (emulator) bulunur. Öykünücü, 8086'yı yazılımla taklit eden bir programdır. Gerçek bir işlemcide yazmaçların içi dışarıdan görünmez; öykünücü ise her komuttan sonra yazmaçları, belleği ve bayrakları ekranda gösterir. Program tek komut ilerletilebilir, geri alınabilir, istenen yerde durdurulabilir. Assembly öğrenirken en değerli araç budur, çünkü her komutun etkisi tahmin edilip hemen sınanabilir.
.COM ve .EXE biçimleri arasındaki fark programın yapısını da belirler. Tablo 3.2.2 iki biçimi karşılaştırır.
| Özellik | .COM | .EXE |
|---|---|---|
| Kesim sayısı | tek kesim; kod, veri ve yığın aynı 64 KB içinde | birden çok kesim (kod, veri, yığın ayrı) |
| Boyut sınırı | 64 KB'tan 256 bayt (PSP) ve yığın payı eksik | 64 KB sınırı her kesim için ayrı |
| Dosya başlığı | yok; dosya belleğe olduğu gibi kopyalanır | var; yer değiştirme tablosu ve başlangıç değerleri içerir |
| Başlangıç adresi | ORG 100h, IP = 0100h | END direktifinde verilen etiket |
| Kesim yazmaçları | CS = DS = ES = SS | DS'yi program kendisi yükler |
Bu notun bütün örnekleri .COM biçimindedir ve emu8086 söz dizimiyle yazılmıştır. Örneklerin çoğu MASM ve TASM ile de aynen derlenir. Komutların bayt değerleri, IP ve yazmaç izlemeleri bir 8086 öykünücüsünde çalıştırılarak elde edilmiştir.
3.2.1.3Assembly ne zaman kullanılır?
Assembly ile yazılan bir program genellikle aynı işi yapan yüksek seviyeli bir programdan küçük ve hızlıdır. Bunun nedeni basittir: programda yalnız programcının yazdığı komutlar bulunur. Derleyicinin eklediği başlatma kodu, kütüphane çağrıları, genel amaçlı yardımcı yordamlar yoktur. Her komutun neden orada olduğu bilinir.
Hızdan daha önemli bir üstünlük, donanıma doğrudan erişimdir. 8086'nın bazı komutlarının standart C'de karşılığı yoktur. OUT bir G/Ç portuna bayt yazar, CLI kesmeleri yasaklar, PUSHF bayrak yazmacını yığına iter. Önyükleyiciler, aygıt sürücüleri, kesme hizmet yordamları ve küçük gömülü sistemler bu yüzden tamamen ya da kısmen assembly ile yazılır. Bilgisayar açıldığında çalışan ilk kod, henüz yığın ve bellek düzeni kurulmadığı için zaten assembly'dir.
Dilin bedeli de ağırdır. Tablo 3.2.3 iki tarafı özetler.
| Artılar | Eksiler |
|---|---|
| Daha az yer kaplar; gereksiz kod yoktur. | Taşınabilir değildir: 8086 kodu ARM işlemcide çalışmaz. |
| Yalnız gereken işlemleri yaptığı için hızlıdır. | Yazması, okuması ve hata ayıklaması zahmetlidir. |
| Port G/Ç, kesme işleme, bayraklara doğrudan erişim sağlar. | Büyük projelerde verim düşüktür. |
| Önyükleyici, sürücü ve gömülü sistemlerde vazgeçilmezdir. | Modern derleyiciler çoğu zaman yeterince hızlı kod üretir. |
Uygulamada bu iki taraf bir arada kullanılır. Programın büyük bölümü C gibi bir dilde yazılır. Zamanlaması kritik küçük parçalar, örneğin bir kesme yordamının girişi ya da sık çağrılan bir döngünün içi, assembly ile yazılır. Bu karma yaklaşım hem geliştirme hızını hem çalışma hızını korur. Assembly bilgisinin bir başka getirisi de yüksek seviyeli kodu okumaktır. Derleyicinin ürettiği assembly çıktısına bakabilen bir mühendis, kodunun neden yavaş çalıştığını ya da bir değişkenin neden beklenmedik bir değer aldığını bulabilir.
“Assembly her zaman daha hızlıdır” sanmak. Elle yazılmış assembly, ancak programcı işlemciyi derleyiciden iyi tanıyorsa hızlıdır. Bellekte tutulan bir döngü sayacı, gereksiz yere yinelenen bellek okumaları ya da yanlış seçilmiş bir komut, iyi bir derleyicinin ürettiği koddan yavaş bir program verir. Hız, dilden çok yazmaç ve bellek kullanımının doğru seçilmesinden gelir.
3.2.2Komut satırının yapısı
3.2.2.1Satırın alanları
Assembly kaynağı satır satır okunur. Her satır en çok bir komut ya da bir direktif taşır. Bir komut satırının genel biçimi şöyledir; köşeli ayraç içindeki alanlar isteğe bağlıdır:
[etiket:] komut [hedef], [kaynak] [; açıklama]Şekil 3.2.2 bu alanları basla: MOV AX, 5 ; AX ← 5 satırı üzerinde gösterir. Etiket satırın adresine verilen addır. Komut alanı anımsatıcıyı taşır. Komuttan sonra virgülle ayrılmış en çok iki işlenen gelir. Noktalı virgülden satır sonuna kadar olan kısım açıklamadır.
basla etiketi, MOV komutu, AX hedef işlenen, 5 kaynak işlenen, noktalı virgülden sonrası açıklamadır. Satırın etkisi AX ← 5 atamasıdır.İşlenen (operand), bir komutun üzerinde işlem yaptığı değer, yazmaç ya da bellek konumudur. İki işlenenli komutlarda Intel söz diziminde soldaki işlenen hedef, sağdaki kaynaktır. Komut kaynağı okur, sonucu hedefe yazar. Kaynak değişmez; hedefin eski değeri kaybolur.
Hedef–kaynak sırası, assembly öğrenen herkesin ilk takıldığı yerdir. MOV AX, BX “AX'i BX'e taşı” diye değil, “AX ← BX” diye okunur. Bu sıra C'deki atama ile aynıdır: ax = bx;. İki işlenenli aritmetik komutlar da aynı kuralı izler. SUB CX, AX çalışınca CX ← CX − AX olur; AX değişmez. Böylece hedef işlenen hem birinci girdi hem de sonucun yazıldığı yerdir.
Her komut iki işlenen almaz. Tablo 3.2.4 farklı sayıda işlenen alan üç satırı alanlarına ayırır.
| Satır | Etiket | Komut | İşlenenler | Açıklama |
|---|---|---|---|---|
basla: MOV AX, 5 ; AX ← 5 | basla | MOV | AX, 5 | ; AX ← 5 |
INC AX | — | INC | AX | — |
RET | — | RET | yok | — |
INC AX tek işlenenlidir: AX hem kaynak hem hedeftir ve AX ← AX + 1 olur. RET hiç işlenen yazmaz, ama yine de iş yapar: yığından bir sözcük okuyup IP'ye koyar. Yazılmayan bu işlenenler örtük işlenenler başlığında ayrıntılı ele alınır.
Assembler büyük-küçük harfe duyarsızdır. mov ax, bx, MOV AX, BX ve Mov Ax, Bx aynı makine kodunu verir. Boşluk ve sekme sayısı da önemsizdir; alanları alt alta hizalamak yalnız okunabilirlik içindir. Açıklamalar ise makine koduna hiç girmez. Assembler noktalı virgülü görünce satırın geri kalanını atlar. Bu yüzden açıklama, programın boyutunu ya da hızını etkilemeden istenildiği kadar uzun yazılabilir.
Assembly'de açıklamanın önemi yüksek seviyeli dillerden fazladır. ADD AX, BX satırı ne yaptığını zaten söyler; neden yapıldığını söylemez. AX'te bir dizi toplamı mı, bir adres mi, bir sayaç mı durduğu koddan anlaşılmaz. İyi bir açıklama “AX ← AX + BX” diye komutu yinelemez, “toplama bu öğrencinin notunu ekle” gibi amacı yazar.
3.2.2.2Komut, direktif ve makro
Bir assembly kaynağındaki her satır makine kodu üretmez. Satırlar üç türe ayrılır.
Komut (instruction), işlemcinin çalışma anında yürüttüğü bir işlemdir ve tek bir makine komutuna çevrilir. Direktif (directive), assembler'a verilen bir bilgidir: kodun nereye yerleşeceğini, ne kadar yer ayrılacağını, bir adın neyi göstereceğini bildirir. Direktif makine komutu üretmez; veri tanımı direktifleri yalnız veri baytı üretir. Makro (macro) ise derleme anında yerine birkaç satır yazılan, adı olan bir metin kalıbıdır.
Komut ile direktif arasındaki fark zamanlamadadır. Komutu, program çalışırken işlemci yürütür. Direktif ise yalnız derleme anında anlam taşır; program çalışmaya başladığında ondan geriye hiçbir iz kalmaz. Tablo 3.2.5 sık kullanılan satırları türleri ve bellekte ürettikleriyle verir.
| Satır | Türü | Bellekte ne üretir? |
|---|---|---|
MOV AX, 5 | komut | makine kodu: B8 05 00 |
ORG 100h | direktif | hiçbir şey; konum sayacını 0100h yapar |
sayi DB 0 | direktif (veri tanımı) | 1 bayt veri: 00 |
k EQU 5 | direktif | hiçbir şey; k adı 5 değerini alır |
END | direktif | hiçbir şey; kaynak burada biter |
PUTC 'A' | makro çağrısı | makro gövdesindeki komutların kodu |
Direktiflerin işleyişini anlamak için assembler'ın konum sayacını (location counter) bilmek gerekir. Assembler kaynağı yukarıdan aşağı okurken bir sonraki baytın yerleşeceği bağıl konumu bir sayaçta tutar. Her komut ya da veri tanımı, ürettiği bayt sayısı kadar sayacı ilerletir. ORG 100h sayacı doğrudan 0100h'ye kurar; kendisi bayt üretmez. EQU ise sayaca hiç dokunmaz: yalnız bir adı bir sabite bağlar. Assembler k adını gördüğü her yerde 5 yazar. sayi DB 0 satırı sayacın o anki değerini sayi adına bağlar, bir bayt ayırır ve içine 0 koyar.
Aşağıdaki küçük program bu farkı somutlaştırır. Sağdaki açıklamalar assembler'ın liste çıktısındaki adresleri ve baytları gösterir.
ORG 100h ; bayt yok; konum sayacı = 0100h
k EQU 5 ; bayt yok; k = 5
MOV AX, 5 ; 0100h: B8 05 00
MOV BX, k ; 0103h: BB 05 00 (k yerine 5)
MOV AL, sayi ; 0106h: A0 0A 01 (sayi = 010Ah)
RET ; 0109h: C3
sayi DB 0 ; 010Ah: 00
END ; bayt yokYedi satırdan yalnız beşi bayt üretir ve program 11 bayttır. MOV AX, 5 ile MOV BX, k satırlarının kodları yazmaç numarası dışında aynıdır, çünkü assembler k yerine 5 koymuştur. EQU ile tanımlanan bir sabit bellekte yer kaplamaz. MOV AL, sayi satırında ise durum farklıdır. sayi bir bellek konumudur; komut o konumdaki baytı okur. Assembler komutun içine konumun adresini yazar: 010Ah, düşük bayt önce 0A 01. Bu adres, assembler sayi satırına gelene kadar bilinmez. Assembler'ın ileriye yapılan bu başvuruyu nasıl çözdüğü iki geçişli çeviriyle açıklanır; burada önemli olan, adresin derleme anında hesaplanıp komutun içine gömülmesidir.
Makro üçüncü türdür. emu8086 ile gelen emu8086.inc kütüphanesindeki PUTC 'A', ekrana bir karakter yazan birkaç komutluk bir kalıbın adıdır. Assembler bu satırı gördüğünde makronun gövdesini satırın yerine kopyalar ve kopyayı çevirir. Makro çağrısı bir altprogram çağrısı değildir: her kullanımda gövde yeniden yazılır ve program o kadar büyür. Makrolar ayrı bir konudur; burada yalnız bir satırın birden çok makine komutu üretebildiği durumu göstermek için anılır.
EQU sabitini değişken sanmak. k EQU 5 tanımından sonra MOV k, 7 yazmak, “5 ← 7” anlamına gelir ve assembler hata verir. EQU adı bellekte yer kaplamaz; değeri derleme anında sabitlenir ve çalışma anında değiştirilemez. Değeri değişecek bir büyüklük DB ya da DW ile tanımlanır.
3.2.2.3Etiketler ve adlar
Assembly programında adresler sayı yerine adlarla yazılır. Bir komutun adresine verilen ada kod etiketi, bir veri alanına verilen ada değişken adı denir. İkisi de assembler'ın sembol tablosunda bir adrese bağlanır; ama kullanılışları farklıdır.
basla: MOV CX, 3 ; kod etiketi
don: INC AX
LOOP don ; don = adres
RET
sayi DB 7 ; veri adıKod etiketi iki nokta üst üste ile biter. Etiket kendisi makine kodu üretmez; yalnız kendisinden sonra gelen komutun adresini, yani CS içindeki bağıl konumunu temsil eder. Bu programın ORG 100h ile başladığı varsayılırsa basla = 0100h olur. MOV CX, 3 üç bayttır (B9 03 00); don = 0103h olur. INC AX tek bayttır (40), LOOP don iki bayttır (E2 FD). RET 0106h'de, sayi ise 0107h'dedir.
LOOP don komutunun ikinci baytı FDh dikkat çekicidir. Komut adresi değil, uzaklığı saklar. LOOP yürütülürken IP zaten sonraki komutu, yani 0106h'yi gösterir. Hedef 0103h olduğundan uzaklık 0103h − 0106h = −3'tür. −3, 8 bitlik ikiye tümleyende FDh olarak yazılır. Etiket programcıyı bu hesaptan kurtarır: programcı don yazar, assembler uzaklığı hesaplar. Programa yeni bir komut eklenip adresler kaydığında da hesap kendiliğinden yenilenir.
Değişken adı iki nokta üst üste olmadan yazılır. Assembler bir değişken adı için üç bilgi saklar: adresi, kesimi ve türü. DB ile tanımlanan bir adın türü bayt, DW ile tanımlananın türü sözcüktür. Tür bilgisi assembler'ın boyut denetimi yapmasını sağlar. sayi DB 7 tanımından sonra MOV AX, sayi yazılırsa assembler, 8 bitlik bir değişkenin 16 bitlik bir yazmaca taşınmak istendiğini fark eder ve hata verir.
Adlar için kurallar şunlardır:
- Ad bir harfle ya da alt çizgiyle başlar; rakamla başlayamaz. Rakamla başlayan her dizi assembler için bir sayıdır.
- Adın devamında harf, rakam ve alt çizgi bulunabilir.
- Komut, yazmaç ve direktif adları (MOV, AX, DB, END …) ad olarak kullanılamaz; bunlar ayrılmış sözcüklerdir.
- Büyük-küçük harf ayrılmaz.
donileDONaynı etikettir; ikisini birden tanımlamak “iki kez tanımlı” hatası verir.
| Ad | Geçerli mi? | Neden? |
|---|---|---|
_sayac | evet | alt çizgiyle başlar |
toplam2 | evet | harfle başlar, rakam sonra gelir |
2toplam | hayır | rakamla başlar; assembler geçersiz bir sayı sanar |
cx | hayır | yazmaç adıdır (CX ile aynı) |
son-deger | hayır | − bir işleçtir; assembler son eksi deger diye okur |
Son satırdaki durum öğreticidir. son-deger bir ifade olarak çözümlenir. Programda son ve deger adları yoksa assembler “tanımsız sembol” hatası verir; varsa iki adresin farkını hesaplar ve programcının hiç istemediği bir sayı üretir. Birden çok sözcükten oluşan adlarda bu yüzden alt çizgi kullanılır: son_deger.
Sayi ile sayi'yı iki ayrı değişken sanmak. C ve Java büyük-küçük harfi ayırır; 8086 assembler'ları ayırmaz. sayi DB 7 tanımından sonra MOV Sayi, 3 yazan programcı yeni bir değişken yarattığını düşünebilir, ama komut aynı bayta 3 yazar ve 7 kaybolur. Assembler bunu hata saymaz, çünkü satır geçerlidir. Farklı büyüklükler farklı adlarla adlandırılır.
3.2.3İşlenenler
3.2.3.1Yazmaç, anlık değer ve bellek
Bir komutun işleneni üç yerden gelebilir: işlemcinin içindeki bir yazmaçtan, komutun kendi baytlarından ya da bellekten. Bu üç tür hem söz diziminde hem donanımda farklı davranır.
| Tür | Örnek | Değer nereden gelir? | Kısıt |
|---|---|---|---|
| Yazmaç | MOV AX, BX | işlemcinin içindeki yazmaç dosyasından | en hızlı tür |
| Anlık değer | MOV AX, 5 | komutun baytlarının içinden | yalnız kaynak olabilir |
| Bellek | MOV AX, [BX] | bellekten, bir yol döngüsüyle | bir komutta en çok bir tane |
Yazmaç işleneni işlemcinin içindedir. 8086'nın yürütme biriminde (EU) sekiz genel amaçlı 16 bitlik yazmaç bulunur: AX, BX, CX, DX, SP, BP, SI ve DI. İlk dördü ayrıca 8 bitlik yarılarıyla kullanılabilir: AH ile AL, BH ile BL, CH ile CL, DH ile DL. Yazmaç işlenenli bir komut dış yola hiç çıkmaz. Değer iç yoldan ALU'ya gider, sonuç yine iç yoldan yazmaca döner.
Anlık değer (immediate value) komutun içine gömülü bir sabittir. MOV AX, 5 komutunun 05 00 baytları bu sabittir. Değer komutla birlikte getirildiği için ayrıca okunması gerekmez; komut kuyruğunda zaten hazırdır. Anlık değer yalnız kaynak olabilir, çünkü bir sabite yazmak anlamsızdır: ADD 5, AX yazımı “5'in yeni değeri 5 + AX olsun” demektir.
Bellek işleneni bir adresle verilir. MOV AX, [BX] komutunda köşeli ayraç “BX'in içindeki sayı bir adrestir; o adresteki sözcüğü al” anlamına gelir. İşlemci önce adresi hesaplar, sonra yol arayüz birimine (BIU) bir okuma isteği verir. BIU adresi adres yoluna koyar, bellekten veriyi okur ve yürütme birimine iletir. Bu dış erişim, yazmaç işlenenine göre en az dört saat turu ek süre getirir.
Üç tür arasındaki temel kurallar şunlardır. İki işlenen aynı boyutta olmalıdır: 8 bitlik bir yazmaca 16 bitlik bir yazmaç taşınamaz. Bir komutta en çok bir bellek işleneni bulunabilir; MOV [BX], [SI] geçersizdir. Kesim yazmaçlarına (CS, DS, ES, SS) anlık değer yüklenemez. Bu kuralların hepsi 8086'nın komut kodlamasından gelir. Komut biçiminde bellek adresini tanımlayan alan bir tanedir; ikinci bir bellek işlenenini kodlayacak yer yoktur. Kesim yazmacına sabit yükleyen bir işlem kodu da tasarlanmamıştır.
Aşağıdaki komutların işlenen türlerini belirleyin: ADD CL, 10, MOV [BX], AX, SUB DX, sayac.
ADD CL, 10: hedef yazmaç (CL), kaynak anlık değer (10). CL ← CL + 10. Bellek erişimi yoktur.
MOV [BX], AX: hedef bellek, kaynak yazmaç. AX'in iki baytı, BX'in gösterdiği adrese düşük bayt önce yazılır. Bir yol döngüsü (yazma) gerekir.
SUB DX, sayac: hedef yazmaç, kaynak bellek (sayac bir değişken adıdır, assembler onu doğrudan adrese çevirir). sayac bir DW değişkeniyse DX ← DX − [sayac] olur; DB değişkeniyse boyut uyuşmazlığı hatası çıkar.
3.2.3.2Örtük işlenenler
Bazı komutlar yazılan işlenenlerin yanında, komut satırında hiç görünmeyen yazmaçları da kullanır ya da değiştirir. Bu yazmaçların hangileri olduğu komutun tanımına gömülüdür.
Örtük işlenen (implicit operand), komut satırında yazılmadığı hâlde komutun okuduğu ya da değiştirdiği yazmaç veya bellek konumudur. Örtük işlenenler komutun işlem kodunda sabittir; programcı onları seçemez, yalnız bilmek zorundadır.
| Komut | Yazılan işlenen | Örtük işlenen(ler) | İşlem |
|---|---|---|---|
MUL BL | BL | AL (çarpılan), AX (sonuç) | AX ← AL × BL |
DIV BL | BL | AX (bölünen), AL (bölüm), AH (kalan) | AL ← AX ÷ BL, AH ← AX mod BL |
LOOP don | don | CX (sayaç) | CX ← CX − 1; CX ≠ 0 ise atla |
CBW | — | AL → AX | AL'nin işaret biti AH'nin bütün bitlerine kopyalanır |
PUSH AX | AX | SS:SP (yığın tepesi) | SP ← SP − 2; [SS:SP] ← AX |
XLAT | — | AL (indis ve sonuç), BX (tablo adresi) | AL ← [DS:BX + AL] |
Tablodaki örtük kullanımlar 8086 yazmaçlarının adlarının da kaynağıdır. AX akümülatördür: çarpma ve bölmenin sonucu her zaman oraya yazılır. CX sayaç yazmacıdır: LOOP onu kendiliğinden azaltır, çok bitli kaydırmalar sayıyı onun alt yarısı CL'den okur. BX taban yazmacıdır: XLAT tablonun başını orada arar. SP yığının tepesini gösterir ve her PUSH ile POP'ta kendiliğinden değişir. Yazmaçların “özel görevleri” aslında bu komutların donanımda sabit bağlantılarıdır. Çarpma devresinin bir girişi doğrudan AL'ye, çıkışı doğrudan AX'e bağlıdır.
Örtük işlenen bilgisinin pratik sonucu şudur: bir komut yazılmayan bir yazmacı da değiştirebilir. MUL BL satırında AH hiç geçmez, ama komut AH'yi siler, çünkü 16 bitlik sonuç AX'in tamamına yazılır. AH'de saklanan bir değer bu satırdan sonra kaybolur. Bir yazmacın değerini korumak isteyen program, kullandığı komutların örtük işlenenlerini bilmek zorundadır.
AX = 100 (0064h) ve BL = 7 iken DIV BL çalışıyor. AL, AH ve AX ne olur?
8 bitlik bölmede bölünen örtük olarak AX'in tamamıdır, bölen yazılan BL'dir. 100 ÷ 7 işleminin bölümü 14, kalanı 2'dir (7 × 14 = 98, 100 − 98 = 2). Bölüm AL'ye, kalan AH'ye yazılır: AL = 0Eh, AH = 02h. İki yarı birlikte okunduğunda AX = 020Eh olur. AX'in bölmeden önceki değeri kaybolmuştur. Bölüm 8 bite sığmasaydı, örneğin AX = 1000 ve BL = 2 olsaydı, işlemci bir bölme hatası kesmesi (INT 0) üretirdi.
AL = F6h iken CBW çalışıyor. AX ne olur? Aynı işi MOV AH, 0 yapsaydı fark ne olurdu?
F6h ikiye tümleyende −10'dur; işaret biti (bit 7) 1'dir. CBW bu biti AH'nin sekiz bitine kopyalar: AH = FFh, AX = FFF6h. FFF6h de 16 bitte −10'dur; işaretli değer korunmuştur. MOV AH, 0 ise AX = 00F6h = 246 verir. Bu sonuç, AL işaretsiz bir sayıysa doğrudur, işaretliyse yanlıştır. CBW'nin tek yazılan işleneni yoktur; hem kaynağı (AL) hem hedefi (AX) örtüktür.
3.2.3.3Kod izleme: MUL, SHR ve LOOP
Aşağıdaki program üç örtük işlenenli komutu art arda kullanır. Programda CX yalnız bir kez yazılır, AX ise hiç yazılmaz gibi görünür. İzleme, bu yazmaçların gerçekte kaç kez değiştiğini gösterir.
ORG 100h
MOV AL, 12
MOV BL, 10
MUL BL ; AX = AL × BL
MOV CL, 2
SHR AX, CL ; sayı CL'de
MOV CX, 3 ; LOOP sayacı
don:
ADD AX, 1
LOOP don ; CX azalır
RETProgramın başında .COM programlarının başlangıç durumu geçerlidir: genel yazmaçlar 0, bayraklar 0'dır. Tablo 3.2.9 her komuttan sonraki durumu verir. Adres sütunu komutun bağıl konumu, bayt sütunu makine kodudur.
| Adres | Baytlar | Komut | AX | BX | CX | CF | ZF | Açıklama |
|---|---|---|---|---|---|---|---|---|
| 0100h | B0 0C | MOV AL, 12 | 000Ch | 0000h | 0000h | 0 | 0 | AL = 12 |
| 0102h | B3 0A | MOV BL, 10 | 000Ch | 000Ah | 0000h | 0 | 0 | BL = 10 |
| 0104h | F6 E3 | MUL BL | 0078h | 000Ah | 0000h | 0 | ? | AX ← AL × BL = 120 |
| 0106h | B1 02 | MOV CL, 2 | 0078h | 000Ah | 0002h | 0 | ? | kaydırma sayısı |
| 0108h | D3 E8 | SHR AX, CL | 001Eh | 000Ah | 0002h | 0 | 0 | 120 ÷ 4 = 30 |
| 010Ah | B9 03 00 | MOV CX, 3 | 001Eh | 000Ah | 0003h | 0 | 0 | CL'deki 2 silindi |
| 010Dh | 05 01 00 | ADD AX, 1 | 001Fh | 000Ah | 0003h | 0 | 0 | 1. tur |
| 0110h | E2 FB | LOOP don | 001Fh | 000Ah | 0002h | 0 | 0 | CX ≠ 0 → don |
| 010Dh | ADD AX, 1 | 0020h | 000Ah | 0002h | 0 | 0 | 2. tur | |
| 0110h | LOOP don | 0020h | 000Ah | 0001h | 0 | 0 | CX ≠ 0 → don | |
| 010Dh | ADD AX, 1 | 0021h | 000Ah | 0001h | 0 | 0 | 3. tur | |
| 0110h | LOOP don | 0021h | 000Ah | 0000h | 0 | 0 | CX = 0 → düşer | |
| 0112h | C3 | RET | 0021h | 000Ah | 0000h | 0 | 0 | sonuç 33 |
MUL adımı. MUL BL satırında yalnız BL yazılıdır. Çarpılan örtük olarak AL'dir (12), sonuç örtük olarak AX'tir. 12 × 10 = 120 = 0078h. Sonuç 8 bite sığdığı için AH = 00h olur ve CF = OF = 0 kalır. 8086'da MUL bu iki bayrağı “sonucun üst yarısı anlamlı mı” sorusuna göre kurar. SF, ZF, AF ve PF ise MUL'den sonra tanımsızdır: işlemci onlara bir değer yazar, ama Intel bu değeri belgelemez. Tabloda ZF için soru işareti bu yüzden konmuştur. Programın ZF'ye güvenmesi için ardından bayrağı tanımlı biçimde kuran bir komut gelmesi gerekir.
SHR adımı. 8086'da bir yazmacı birden fazla bit kaydırmak için kaydırma sayısı yalnız CL'de verilebilir. SHR AX, 2 biçimi 80186 ile geldi. Program bu yüzden önce MOV CL, 2 yazar. Sağa kaydırma her bitte değeri ikiye böler: 0078h = 0111 1000b iki bit sağa kayınca 0001 1110b = 001Eh = 30 olur. Kaydırmada son dışarı çıkan bit CF'ye yazılır. Çıkan iki bit 0 ve 0 olduğu için CF = 0'dır. Sonuç sıfır olmadığından ZF = 0 olur. Bu komutla ZF yeniden tanımlı hâle gelmiştir.
MOV CX, 3 adımı. Bu satır CX'e 3 yazar. CL, CX'in alt yarısıdır; bir önceki adımda CL'ye yazılan 2 böylece silinir. Kaydırma bittiği için kayıp önemsizdir, ama sıra ters olsaydı, yani CX önce kurulup sonra CL'ye 2 yazılsaydı, döngü 3 kez değil 2 kez dönerdi. Aynı fiziksel yazmacın iki adla anılması, örtük işlenenlerle birleşince sık hata kaynağı olur.
LOOP adımları. LOOP don komutu iki işi tek komutta yapar: CX'i 1 azaltır ve CX sıfır değilse don etiketine atlar. Programda CX'i azaltan hiçbir satır yoktur, ama izleme CX'in 3 → 2 → 1 → 0 diye üç kez değiştiğini gösterir. LOOP'un azaltması bayrakları etkilemez; LOOP bayrak değiştirmeyen bir komuttur. Her turda ADD AX, 1 AX'i bir artırır: 30 → 31 → 32 → 33. Üçüncü LOOP'ta CX sıfıra iner, atlama yapılmaz ve akış RET'e düşer.
Programın sonunda AX = 0021h = 33'tür. Sonuç satır satır okununca şaşırtıcı değildir, ama programda AX'in yalnız ADD satırında yazıldığını düşünen biri MUL ve SHR'nin AX'i değiştirdiğini kaçırır. Şekil 3.2.3 izlemenin üç anını sunumdaki çizimlerle gösterir.
MUL BL sonrası: AX = 0078h, ZF tanımsız. Ortada SHR AX, CL sonrası: AX = 001Eh, CX = 0002h. Altta RET'te: AX = 0021h, CX = 0000h. Vurgulu kutular o adımda değişen yazmaçlardır.MUL'ün AH'yi koruduğunu sanmak. AH'de bir sayaç ya da ara sonuç tutan bir program MUL BL çalıştırınca bu değeri kaybeder. 16 bitlik MUL BX ise daha da geniş bir alanı değiştirir: sonuç DX:AX çiftine yazılır ve DX'in eski değeri de silinir. Saklanması gereken yazmaç MUL'den önce başka bir yazmaca ya da yığına alınır.
3.2.3.4Yazmaç mı, bellek mi?
Bir değer ya yazmaçta ya bellekte tutulur. İkisi arasındaki seçim, programın hızını en çok etkileyen karardır. Şekil 3.2.4 iki yerin işlemciye uzaklığını gösterir.
8086'nın programcıya görünen 14 yazmacı vardır: 8 genel amaçlı yazmaç (AX, BX, CX, DX, SP, BP, SI, DI), 4 kesim yazmacı (CS, DS, ES, SS), komut işaretçisi IP ve bayrak yazmacı FLAGS. Hepsi 16 bittir. Yazmaçlar flip-flop'lardan yapılmış küçük ve çok hızlı bellek hücreleridir. Bir yazmacın değeri iç yoldan doğrudan ALU'ya ulaşır; dış hatlara hiç çıkmaz.
Bellek ise CPU'nun dışındadır ve 8086'da 1 MB'a kadar büyüyebilir. Program kodu, değişkenler, diziler ve yığın burada durur. Bellekten bir sözcük okumak için işlemcinin bir yol döngüsü (bus cycle) yürütmesi gerekir.
Yol döngüsü, işlemcinin sistem yolu üzerinden bir bellek ya da G/Ç konumunu okuduğu veya yazdığı işlemdir. 8086'da bir yol döngüsü en az dört T durumundan (T1–T4) oluşur; her T durumu bir saat turudur. Bellek yavaşsa T3 ile T4 arasına bekleme durumları (Tw) eklenir.
Bir okuma döngüsünde T1'de işlemci 20 bitlik adresi AD0–AD15 ve A16–A19 hatlarına koyar ve ALE sinyaliyle adresin dış kilitlere yakalanmasını sağlar. T2'de aynı hatlar veri için serbest bırakılır ve RD sinyali etkin olur. T3'te bellek veriyi veri yoluna koyar. T4'te işlemci veriyi alır ve sinyaller geri çekilir. Yazmaç işleneninde bu dört adımın hiçbiri yoktur. Bellek erişimi bu yüzden yazmaç erişiminden kat kat uzundur.
Bellek erişiminin bir bedeli daha vardır. 8086'nın veri yolu 16 bittir ve bir yol döngüsünde çift adresten başlayan bir sözcüğü bütün olarak okuyabilir. Sözcük tek adreste başlıyorsa iki ayrı yol döngüsü gerekir: biri düşük bayt, biri yüksek bayt için. Bu durumda erişim dört saat turu daha uzar.
Bu fark iyi assembly kodunun kuralını belirler: sık kullanılan değerler yazmaçlarda tutulur, belleğe yalnız gerektiğinde gidilir. Bir döngü sayacını bellekte değil CX'te tutmak döngüyü hızlandırır. Bir dizinin elemanları bellekte durmak zorundadır, ama elemanların toplamı döngü boyunca bir yazmaçta biriktirilip en sonda belleğe bir kez yazılabilir.
3.2.3.5Komut süreleri
Intel 8086 veri sayfası her komutun kaç saat turu sürdüğünü verir. Bellek işlenenli komutlarda bu süreye, adresin hesaplanması için bir etkin adres (EA) süresi eklenir. Etkin adres, bellek işleneninin kesim içindeki bağıl konumudur; doğrudan bir sabit, bir yazmaç ya da yazmaç ve sabit toplamı olabilir.
| Komut | İşlenenler | Saat turu |
|---|---|---|
MOV AX, BX | yazmaç, yazmaç | 2 |
MOV AX, 5 | yazmaç, anlık | 4 |
MOV AX, sayi | akümülatör, doğrudan bellek | 10 |
MOV CX, [BX] | yazmaç, bellek | 8 + 5 = 13 |
ADD AX, BX | yazmaç, yazmaç | 3 |
ADD AX, sayi | yazmaç, bellek | 9 + 6 = 15 |
INC CX | 16 bitlik yazmaç | 2 |
INC sayac | bellek (sözcük) | 15 + 6 = 21 |
| Adres biçimi | Örnek | EA süresi (tur) |
|---|---|---|
| yalnız taban ya da indis | [BX], [SI] | 5 |
| doğrudan adres | sayi, [0200h] | 6 |
| taban + indis | [BX+SI], [BP+DI] | 7 |
| taban + indis | [BX+DI], [BP+SI] | 8 |
| taban ya da indis + sabit | [BX+4] | 9 |
Tablodaki farkların nedeni donanımdır. MOV AX, BX bir iç aktarımdır: 2 tur. MOV AX, 5 4 tur sürer, çünkü 16 bitlik sabit komut kuyruğundan çekilmelidir. MOV CX, [BX] önce etkin adresi hesaplar (5 tur), sonra bir yol döngüsü yürütür. MOV AX, sayi özel bir durumdur. AX'e doğrudan adresten yükleme, adresi komutun içinde taşıyan kısa akümülatör biçimini (A1 işlem kodu) kullanır ve EA hesabı gerektirmez: 10 tur. Belleğe yazan komutlar en uzunlarıdır. INC sayac önce sözcüğü okur, ALU'da artırır, sonra geri yazar; iki yol döngüsü içerir ve 21 tur sürer.
Tablodaki değerler en iyi durum süreleridir. Tek adresteki sözcük erişimi her erişime 4 tur ekler. Bir atlamadan sonra komut kuyruğu boşalmışsa işlemci baytların gelmesini bekler. Kesim öneki kullanılırsa 2 tur daha eklenir. Gerçek süre bu yüzden tablodakinden uzun olabilir. Oran ise değişmez: bellek işlenenli bir komut, yazmaç işlenenli eşinden birkaç kat yavaştır.
5 MHz'lik bir 8086'da 1000 kez dönen bir döngüde sayaç her turda bir kez artırılıyor. Sayaç CX'te ve bellekte tutulduğunda artırma işlemleri toplam ne kadar sürer?
5 MHz'de bir saat turu 1 / (5 × 106) s = 0,2 µs'dir. Sayaç CX'teyse her artırma INC CX ile 2 tur sürer: 1000 × 2 = 2000 tur = 2000 × 0,2 µs = 0,4 ms. Sayaç bellekteyse her artırma INC sayac ile 21 tur sürer: 1000 × 21 = 21 000 tur = 4,2 ms. Yalnız sayacın yeri değişmiş, süre on kattan fazla artmıştır. Döngünün öteki komutları aynı kaldığı için toplam süredeki fark da 3,8 ms'dir.
MOV AX, 5, MOV BX, 3, ADD AX, BX, MOV CL, AL dizisi kaç saat turu sürer? İkinci satır MOV BX, sayi (doğrudan adres, sözcük) olsaydı ne değişirdi?
Yazmaça anlık değer 4, yazmaçtan yazmaca toplama 3, 8 bitlik yazmaçtan yazmaca MOV 2 tur sürer: 4 + 4 + 3 + 2 = 13 tur; 5 MHz'de 2,6 µs. İkinci satır bellekten okursa ve hedef AX değil BX olduğu için akümülatör biçimi kullanılamaz; süre 8 + 6 = 14 tur olur. Toplam 4 + 14 + 3 + 2 = 23 tur, yani 4,6 µs çıkar. Tek bir bellek işleneni dizinin süresini yaklaşık iki katına çıkarmıştır.
Komut uzunluğu ile süresini karıştırmak. Kısa komut hızlı komut demek değildir. MUL BL yalnız iki bayttır (F6 E3), ama 70–77 saat turu sürer; üç baytlık ADD AX, 1234h (05 34 12) ise 4 turdur. Bayt sayısı komutun bellekte kapladığı yeri ve IP'nin ne kadar ilerleyeceğini belirler. Süreyi ise komutun iç işlemi ve yol döngüsü sayısı belirler.
3.2.4IP ve bayraklar
3.2.4.1IP nasıl ilerler?
Programlarda IP hiç yazılmaz, ama her komut onu değiştirir. Komut işaretçisi (IP, instruction pointer), sıradaki komutun kod kesimi içindeki bağıl konumunu tutar. Fiziksel adres CS ile IP'den hesaplanır: CS × 10h + IP. Bu çifte CS:IP denir.
Sıradan (atlama yapmayan) bir komut yürütüldükten sonra IP, komutun bayt uzunluğu kadar ilerler: IPyeni = IPeski + komut uzunluğu. Atlama, çağrı, dönüş ve kesme komutları ise IP'ye yeni bir değer yazar. IP'ye MOV ile yazılamaz.
8086 komutları 1 ile 6 bayt arasında değişen uzunluktadır. IP'nin ne kadar ilerleyeceğini bilmek için her komutun uzunluğunu bilmek gerekir. Aşağıdaki programda uzunluklar açıklama olarak yazılmıştır.
ORG 100h
MOV AX, 5 ; 3 bayt
MOV BX, 2 ; 3 bayt
INC AX ; 1 bayt
ADD AX, BX ; 2 bayt
RET ; 1 bayt| Adım | Komutun adresi | Baytlar | Komut | IP | AX | BX | SP |
|---|---|---|---|---|---|---|---|
| 0 | — | — | (yüklendi) | 0100h | 0000h | 0000h | FFFEh |
| 1 | 0100h | B8 05 00 | MOV AX, 5 | 0103h | 0005h | 0000h | FFFEh |
| 2 | 0103h | BB 02 00 | MOV BX, 2 | 0106h | 0005h | 0002h | FFFEh |
| 3 | 0106h | 40 | INC AX | 0107h | 0006h | 0002h | FFFEh |
| 4 | 0107h | 03 C3 | ADD AX, BX | 0109h | 0008h | 0002h | FFFEh |
| 5 | 0109h | C3 | RET | 0000h | 0008h | 0002h | 0000h |
Adım 0'da program kesimin 0100h konumuna yüklenmiştir ve IP = 0100h ilk komutu gösterir. Adım 1'de işlemci B8 baytını okur, bu işlem kodunun arkasından iki baytlık bir sabit geleceğini anlar ve üç baytı birlikte alır. IP 0103h'ye ilerler; komut yürütülünce AX = 0005h olur. Adım 2'de aynı şey BX için olur: 3 bayt daha, IP = 0106h.
Adım 3'teki INC AX tek bayttır. 16 bitlik yazmacı artırma komutlarının kodu 40h + yazmaç numarasıdır; AX için 40h. IP yalnız 1 artar: 0107h. Adım 4'te ADD AX, BX iki bayttır: işlem kodu 03h ve işlenenleri tanımlayan bir bayt (C3h). IP = 0109h, AX = 0006h + 0002h = 0008h olur.
Adım 5 sıradan bir komut değildir. RET yığının tepesindeki sözcüğü IP'ye alır. .COM programı başladığında yığının tepesinde (SS:FFFEh) DOS'un koyduğu 0000h vardır. RET bu değeri IP'ye yazar ve SP'yi 2 artırır: FFFEh + 2 = 10000h, 16 bite sığmadığı için SP = 0000h olur. IP = 0000h artık programın değil, kesimin başındaki PSP'nin ilk baytını gösterir. Orada INT 20h komutu (CD 20) durur ve programı bitirir.
IP ile donanım arasındaki ilişki burada bir inceliği gizler. 8086'nın yol arayüz birimi komut baytlarını önceden getirir ve 6 baytlık bir kuyrukta bekletir. BIU'nun bellekten okuduğu adres, yürütülen komutun adresinden birkaç bayt ileridedir. Programcının gördüğü IP ise her zaman yürütülecek sıradaki komutun adresidir. Bir atlama olduğunda kuyruk boşaltılır ve BIU yeni IP'den getirmeye başlar. Kuyruk programcıya görünmez; yalnız sürelere yansır.
Bir program 0100h'de başlıyor ve uzunlukları 3, 2, 1 ve 4 bayt olan dört komutu sırayla yürütüyor. Komutların hiçbiri atlama değildir. Dördüncü komuttan sonra IP kaçtır? Üçüncü komutun adresi nedir?
IP her komutta uzunluğu kadar ilerler: 0100h → 0103h → 0105h → 0106h → 010Ah. Dört komut toplam 3 + 2 + 1 + 4 = 10 bayttır ve IP = 0100h + 0Ah = 010Ah olur. Üçüncü komut, ilk iki komutun bittiği yerde, 0105h adresinde başlar.
IP'yi komut sayısıyla ilerletmek. “Üç komut yürütüldü, IP 0103h olur” düşüncesi yanlıştır. IP baytları sayar, komutları değil. 8086'da komut uzunlukları değişken olduğu için IP'yi hesaplamak, her komutun uzunluğunu bilmeyi gerektirir. Uzunluklar emu8086'nın bellek görünümünden ya da assembler'ın liste çıktısından okunabilir.
3.2.4.2Bayrakları hangi komutlar değiştirir?
Bayrak yazmacı (FLAGS), son aritmetik ya da mantık işleminin sonucu hakkında bilgi taşır. Durum bayrakları şunlardır: CF (elde), ZF (sıfır), SF (işaret), OF (taşma), AF (yardımcı elde) ve PF (eşlik). Koşullu atlama komutları bu bayraklara bakarak karar verir. Hangi komutun hangi bayrağı değiştirdiği bu yüzden programın akışını doğrudan belirler.
Temel kural, bayrakların yalnız sonuç hesaplayan komutlarca yazılmasıdır. Veri taşıyan komutlar sonuç hesaplamaz; bayraklara dokunmaz. Tablo 3.2.13 komutları bayraklara etkilerine göre gruplar.
| Grup | Komutlar | Etki |
|---|---|---|
| Veri taşıma | MOV, XCHG, LEA, PUSH, POP, CBW | hiçbir bayrak değişmez |
| Döngü ve atlama | JMP, Jcc, LOOP, CALL, RET | hiçbir bayrak değişmez |
| Değil | NOT | hiçbir bayrak değişmez |
| Artırma, azaltma | INC, DEC | ZF, SF, OF, AF, PF yeniden yazılır; CF değişmez |
| Toplama, çıkarma, karşılaştırma | ADD, ADC, SUB, SBB, CMP, NEG | altı durum bayrağı yeniden yazılır |
| Mantık | AND, OR, XOR, TEST | CF = OF = 0; ZF, SF, PF sonuca göre |
| Çarpma | MUL, IMUL | CF, OF tanımlı; ZF, SF, AF, PF tanımsız |
| Doğrudan kurma | STC, CLC, CMC | yalnız CF |
Tablonun iki satırı şaşırtıcıdır. Birincisi NOT'tur. NOT bir mantık işlemidir ve yeni bir değer hesaplar, ama 8086'da hiçbir bayrağı değiştirmez. NOT sonrası sonucu sınamak isteyen program ardından TEST AL, AL ya da CMP yazmalıdır. İkincisi INC ve DEC'tir. Bu iki komut CF'ye dokunmaz. Tasarımın amacı çok baytlı sayılar üzerinde çalışan döngülerdir: döngü sayacı ya da indis INC/DEC ile değiştirilirken ADC'nin taşıdığı elde kaybolmaz. INC'in bir sayıyı FFFFh'den 0000h'ye geçirdiğini anlamak için CF'ye değil ZF'ye bakılır.
Bir koşullu atlamanın baktığı bayrak, ondan önce yürütülen ve o bayrağı yazan son komutun sonucunu gösterir. Aradaki MOV, NOT, LOOP gibi bayrak değiştirmeyen komutlar bu ilişkiyi bozmaz; ama aradaki bir INC, ADD ya da CMP bozar.
3.2.4.3Kod izleme: bayraklar
Aşağıdaki program bayrak kurallarını tek tek sınar. Her satırdaki açıklama o satırın bayraklara etkisini önceden söyler; izleme bu tahminleri doğrular.
ORG 100h
STC ; CF = 1
MOV AL, 0FFh ; bayraklar aynı
INC AL ; CF'ye dokunmaz
MOV CX, 0 ; ZF aynı kalır
DEC AL
ADD AL, 1 ; CF yeni
CLC
NOT AL ; bayraklar aynı
RET| Adres | Baytlar | Komut | AL | CF | ZF | SF | OF | AF | PF | Hangi bayraklar yazıldı? |
|---|---|---|---|---|---|---|---|---|---|---|
| 0100h | F9 | STC | 00h | 1 | 0 | 0 | 0 | 0 | 0 | yalnız CF |
| 0101h | B0 FF | MOV AL, 0FFh | FFh | 1 | 0 | 0 | 0 | 0 | 0 | hiçbiri |
| 0103h | FE C0 | INC AL | 00h | 1 | 1 | 0 | 0 | 1 | 1 | CF dışındakiler |
| 0105h | B9 00 00 | MOV CX, 0 | 00h | 1 | 1 | 0 | 0 | 1 | 1 | hiçbiri |
| 0108h | FE C8 | DEC AL | FFh | 1 | 0 | 1 | 0 | 1 | 1 | CF dışındakiler |
| 010Ah | 04 01 | ADD AL, 1 | 00h | 1 | 1 | 0 | 0 | 1 | 1 | hepsi |
| 010Ch | F8 | CLC | 00h | 0 | 1 | 0 | 0 | 1 | 1 | yalnız CF |
| 010Dh | F6 D0 | NOT AL | FFh | 0 | 1 | 0 | 0 | 1 | 1 | hiçbiri |
STC ve MOV. STC (set carry) CF'yi doğrudan 1 yapar. Bayrağı bir işlem sonucu olmadan değiştiren az sayıdaki komuttan biridir. MOV AL, 0FFh AL'ye 255 yazar; bayrakların hiçbiri değişmez. MOV bir sonuç hesaplamaz, yalnız kopyalar.
INC AL. FFh + 1 = 100h, 8 bite sığmaz ve AL = 00h olur. Toplama bir ADD ile yapılsaydı bu elde CF'ye yazılırdı. INC ise CF'ye dokunmaz; CF, STC'den kalan 1'dir. Sonuç sıfır olduğu için ZF = 1, bit 3'ten bit 4'e elde geçtiği için AF = 1 olur. 00h'nin bir bitlerinin sayısı sıfırdır, yani çifttir; PF = 1. İşaretli yorumda −1 + 1 = 0 doğru bir sonuçtur, taşma yoktur: OF = 0.
MOV CX, 0. CX'e sıfır yazılır. Sonuç sıfır olduğu hâlde ZF yeniden hesaplanmaz; ZF'deki 1 bir önceki INC'ten kalmıştır. Bu satırdan sonra bir JZ gelseydi atlama yapılırdı, ama nedeni CX değil AL olurdu.
DEC AL. 00h − 1 = FFh. En üst bit 1 olduğu için SF = 1, sonuç sıfır olmadığı için ZF = 0 olur. Bit 4'ten ödünç alındığı için AF = 1, FFh'nin sekiz bir biti çift sayıda olduğu için PF = 1'dir. İşaretsiz yorumda 0'dan 1 çıkarmak bir ödünç doğurur. SUB bunu CF'ye yazardı; DEC yazmaz ve CF yine 1 kalır.
ADD AL, 1. FFh + 1 = 100h, AL = 00h. Bu kez toplamayı ADD yapar ve ADD altı durum bayrağının hepsini yeniden yazar. CF = 1 olur; tablodaki değer önceki satırla aynı görünür, ama artık STC'den kalan 1 değil, ADD'in ürettiği eldedir. ZF = 1, SF = 0, AF = 1, PF = 1, OF = 0.
CLC ve NOT. CLC CF'yi 0 yapar. NOT AL AL'nin bütün bitlerini ters çevirir: 00h → FFh. AL sıfır olmaktan çıktığı hâlde ZF hâlâ 1'dir, çünkü NOT bayrak yazmaz. Bu satırdan sonra AL'nin sıfır olup olmadığını sınamak için TEST AL, AL gerekir.
INC AL sonrası: AL = 00h, ZF = 1, CF korunmuştur. Ortada DEC AL sonrası: AL = FFh, SF = 1, CF yine korunmuştur. Altta NOT AL sonrası: AL = FFh olduğu hâlde ZF = 1 kalmıştır.Koşullu atlamadan önce bayrağı kimin kurduğuna bakmamak. DEC CX ile JZ son arasına bir MOV AX, [BX] eklemek akışı bozmaz; MOV bayrak yazmaz. Araya bir ADD SI, 2 eklemek ise bozar: JZ artık CX'e değil SI'nin toplamına bakar. Atlamadan önce “bu bayrağı en son hangi komut yazdı?” sorusu sorulmalıdır.
3.2.5İlk program
3.2.5.1.COM program şablonu
emu8086'da yeni bir dosya açılırken COM template seçilirse düzenleyici boş bir .COM şablonuyla açılır. Bir .COM programının iskeleti yalnız üç parçadan oluşur: başlangıç konumunu bildiren ORG 100h, komutlar ve programı bitiren RET. Değişkenler, varsa, RET'ten sonra gelir.
ORG 100h ; .COM: kod 0100h'den başlar
MOV AX, 5 ; AX = 5
MOV BX, 3 ; BX = 3
ADD AX, BX ; AX = AX + BX = 8
MOV CL, AL ; CL = 08h
RET ; DOS'a dön
sayi DB 0 ; değişkenler RET'ten sonraORG 100h. DOS bir .COM programını yüklerken önce bir kesim seçer ve bu kesimin ilk 256 baytına (0000h–00FFh) PSP (program segment prefix, program kesimi öneki) adlı bir başlık yazar. PSP'de programın komut satırı, bitiş adresi ve DOS'un kullandığı başka bilgiler bulunur. Programın baytları PSP'nin hemen arkasına, 0100h'den başlayarak kopyalanır. ORG 100h assembler'a bu gerçeği bildirir. Direktif olmasaydı assembler ilk baytı 0000h'de sanar ve bütün değişken adreslerini 256 bayt eksik hesaplardı.
Sıralı yürütme. Komutlar yukarıdan aşağı sırayla yürütülür. Bir atlama komutu yoksa işlemci her komuttan sonra bellekte hemen arkasındaki baytlara geçer. Boş satırlar ve açıklamalar bu sıraya hiçbir şey eklemez.
RET. Program bitince denetimin işletim sistemine dönmesi gerekir. RET bu işi dolaylı yoldan yapar: yığından 0000h'yi IP'ye alır, işlemci PSP'nin başındaki INT 20h komutunu yürütür ve DOS programı sonlandırır. RET unutulursa işlemci programın bittiğini bilemez. Komutların arkasındaki baytları, yani değişkenleri ve onların arkasındaki rastgele bellek içeriğini, komut gibi çözmeye devam eder.
Değişkenlerin yeri. Bu yüzden değişkenler kodun sonuna, RET'in arkasına konur. RET'e gelen işlemci geri döner ve değişkenlerin baytlarına hiç ulaşmaz. Değişkenler kodun önüne konmak istenirse ilk komut, verinin üstünden atlayan bir JMP olmalıdır.
Başlangıç durumu. .COM programı tek kesimlidir: kod, veri ve yığın aynı 64 KB'tadır. Yükleyici bu yüzden dört kesim yazmacına aynı değeri koyar: CS = DS = ES = SS. emu8086 bu değer olarak 0700h kullanır. IP = 0100h, SP = FFFEh olur; yığın kesimin en sonundan başlayıp aşağı doğru büyür. Yığının tepesinde, FFFEh adresinde, RET'in dönüşünü sağlayan 0000h sözcüğü durur. Genel yazmaçlar sıfırdır.
| Yazmaç | Değer | Anlamı |
|---|---|---|
| CS, DS, ES, SS | 0700h | tek kesim; kesim 07000h fiziksel adresinde başlar |
| IP | 0100h | PSP'nin arkasındaki ilk komut |
| SP | FFFEh | yığının tepesi; [FFFEh] = 0000h |
| AX, BX, CX, DX, SI, DI, BP | 0000h | — |
| FLAGS | IF = 1, ötekiler 0 | kesmeler açık |
Şablondaki dört komutun işi basittir: AX'e 5, BX'e 3 yazılır, ikisi toplanır ve sonucun alt baytı CL'ye kopyalanır. Programın amacı bir hesap değil, bir .COM programının bellekte nasıl durduğunu ve nasıl çalıştığını göstermektir.
3.2.5.2Kod izleme: .COM programı bellekte
Tablo 3.2.16 şablon programın her komuttan sonraki durumunu verir. Fiziksel adres sütunu, kesim 0700h için 07000h + bağıl konumdur.
| Adım | Komut (adres) | Fiziksel adres | AX | BX | CL | IP | SP |
|---|---|---|---|---|---|---|---|
| 0 | (yüklendi) | — | 0000h | 0000h | 00h | 0100h | FFFEh |
| 1 | MOV AX, 5 (0100h) | 07100h | 0005h | 0000h | 00h | 0103h | FFFEh |
| 2 | MOV BX, 3 (0103h) | 07103h | 0005h | 0003h | 00h | 0106h | FFFEh |
| 3 | ADD AX, BX (0106h) | 07106h | 0008h | 0003h | 00h | 0108h | FFFEh |
| 4 | MOV CL, AL (0108h) | 07108h | 0008h | 0003h | 08h | 010Ah | FFFEh |
| 5 | RET (010Ah) | 0710Ah | 0008h | 0003h | 08h | 0000h | 0000h |
| 6 | INT 20h (PSP, 0000h) | 07000h | program biter | ||||
Adım 1–4 sıradan komutlardır ve IP her birinde komut uzunluğu kadar ilerler: 3, 3, 2 ve 2 bayt. Adım 3'teki toplama bayrakları da yazar: 5 + 3 = 8, sonuç sıfır değil (ZF = 0), işaret biti 0 (SF = 0), elde ve taşma yok (CF = OF = 0). 08h'de tek bir 1 biti olduğu için eşlik tektir ve PF = 0'dır. Adım 4'teki MOV CL, AL AX'in alt baytını CL'ye kopyalar; CH değişmez ve CX = 0008h olur.
Adım 5'te RET yığından sözcük okur. SS:SP = 0700:FFFEh, yani fiziksel 16FFEh adresindeki sözcük 0000h'dir. Bu değer IP'ye yazılır, SP 2 artarak 0000h'ye döner. Adım 6'da işlemci 0700:0000'daki iki baytı, CD 20'yi, yani INT 20h'yi yürütür. DOS'un sonlandırma hizmeti programı bellekten kaldırır. 010Bh'deki sayi baytı hiçbir adımda yürütülmemiştir; yalnız veridir.
sayi 010Bh'de, yığının tepesi FFFEh'dedir; CS:IP ilk komutu, SS:SP yığının tepesini gösterir. Altta RET yürütülmüş, IP = 0000h ile PSP'ye dönülmüştür.Bu izleme, sistem yolu açısından da okunabilir. Her komutun baytlarını BIU kod kesiminden getirir. Getirme için kullanılan fiziksel adres CS × 10h + IP'dir: 07000h + 0100h = 07100h ilk bayt için. Programın dört aritmetik komutu bellekten veri okumaz; işlenenlerin hepsi yazmaç ya da anlık değerdir. Veri için yol döngüsü yalnız RET'te yapılır: yığından bir sözcük okunur. RET aynı zamanda bir atlamadır; komut kuyruğu boşaltılır ve BIU getirmeye 07000h'den yeniden başlar.
3.2.5.3Program bellekte: bayt bayt
Assembler'ın şablon programdan ürettiği baytlar Tablo 3.2.17'deki gibidir. Bir .COM dosyası tam olarak bu baytlardan oluşur.
| Bağıl konum | Baytlar | Kaynak satırı | Çözümleme |
|---|---|---|---|
| 0100h | B8 05 00 | MOV AX, 5 | B8 + yazmaç no (AX = 0); sabit düşük bayt önce |
| 0103h | BB 03 00 | MOV BX, 3 | B8 + 3 (BX) |
| 0106h | 03 C3 | ADD AX, BX | C3 = 11 000 011: yazmaç–yazmaç, AX, BX |
| 0108h | 8A C8 | MOV CL, AL | C8 = 11 001 000: CL, AL |
| 010Ah | C3 | RET | tek baytlık komut |
| 010Bh | 00 | sayi DB 0 | veri; komut değil |
İlk iki komut “yazmaca anlık değer” ailesindendir ve işlem kodu yazmaç numarasını içerir. 8086'nın 16 bitlik yazmaç numaraları şöyledir: AX = 0, CX = 1, DX = 2, BX = 3, SP = 4, BP = 5, SI = 6, DI = 7. Sıranın alfabetik olmadığına dikkat edilmelidir; BX'in numarası 3'tür. 8 bitlik yazmaçlarda aynı numaralar AL, CL, DL, BL, AH, CH, DH, BH sırasıyla kullanılır.
Üçüncü ve dördüncü komut iki yazmaç arasında çalışır. Bu komutlarda ilk bayt işlemi, ikinci bayt işlenenleri tanımlar. İkinci bayta ModR/M baytı denir ve üç alana bölünür: 2 bitlik MOD, 3 bitlik REG ve 3 bitlik R/M. MOD = 11 “iki işlenen de yazmaç” demektir. ADD AX, BX için işlem kodu 03h “REG ← REG + R/M” biçimindedir. REG = 000 (AX) hedefi, R/M = 011 (BX) kaynağı verir. Bitler birleşince 11 000 011 = C3h olur. MOV CL, AL için işlem kodu 8Ah “8 bitlik REG ← R/M” biçimidir. REG = 001 (CL), R/M = 000 (AL) olur ve 11 001 000 = C8h çıkar.
ADD DX, CX ve MOV BL, AH komutlarının makine kodları nedir?
ADD DX, CX: işlem kodu 03h (REG ← REG + R/M), MOD = 11, REG = DX = 010, R/M = CX = 001. ModR/M = 11 010 001 = D1h. Komut 03 D1 olur.
MOV BL, AH: işlem kodu 8Ah, MOD = 11, REG = BL = 011, R/M = AH = 100. ModR/M = 11 011 100 = DCh. Komut 8A DC olur. İki komut da iki bayttır; IP her birinde 2 ilerler.
Tablodan çıkan dört sonuç önemlidir. Birincisi, .COM dosyası tam olarak bu 12 bayttır. Başlık yoktur; DOS dosyanın baytlarını olduğu gibi 0100h'den itibaren belleğe kopyalar. İkincisi, ORG 100h satırının karşılığında hiçbir bayt yoktur; direktif yalnız ilk baytın konumunu belirler.
Üçüncüsü, aynı komutun birden çok kodlaması olabilir. 8086'nın yazmaç–yazmaç komutlarında yön biti vardır: 03h “REG hedeftir”, 01h “R/M hedeftir” anlamına gelir. ADD AX, BX 01h ile de yazılabilir; bu durumda REG = BX, R/M = AX olur ve kod 01 D8 çıkar. MASM 03 C3'ü seçer, başka bir assembler 01 D8'i seçebilir. İkisi de aynı işi aynı sürede yapar. Liste çıktısı farklı assembler'larda bu yüzden farklı baytlar gösterebilir.
Dördüncüsü ve en önemlisi, bellekte komut ile veri arasında hiçbir işaret yoktur. 010Bh'deki 00 baytı bir değişkendir, ama işlemci IP = 010Bh ile oraya gelseydi onu bir komut olarak çözerdi. 8086'da 00h, bir ADD komutunun işlem kodudur ve arkasından gelen bayt ModR/M olarak okunurdu. Bir baytın komut mu veri mi olduğunu yalnız programın akışı belirler. Değişkenlerin RET'ten sonra konmasının nedeni budur.
Değişkenleri ORG 100h'ın hemen altına yazmak. Yüksek seviyeli dillerde değişkenler programın başında tanımlanır; bu alışkanlık assembly'ye taşınınca program çalışmaz. sayi DB 0 0100h'ye yerleşir ve işlemci ilk komut olarak 00h baytını, yani bir ADD'in başını yürütür. Sonuç rastgele bir bellek yazması ve kaymış komut sınırlarıdır. Veri ya RET'ten sonra konur ya da kodun başında bir JMP ile üstünden atlanır.
3.2.5.4emu8086 öykünücü penceresi
Kaynak yazıldıktan sonra emu8086'da emulate düğmesi programı derler ve öykünücü penceresine yükler. Şekil 3.2.8 bu pencerenin ana bölümlerini sade bir çizimle gösterir.
MOV BX, 00003h'tür.Pencerenin bölümleri şunlardır:
- Denetim düğmeleri. single step bir komut yürütür ve durur; değişen yazmaçlar ve bellek hemen görünür. step back son adımı geri alır; bir hatanın nedenine geri dönmeyi kolaylaştırır. run programı sonuna kadar çalıştırır, reload programı baştan yükler.
- Yazmaçlar. Her yazmaç yüksek (H) ve düşük (L) baytı ayrı ayrı gösterilir: AX = 0005h, “00 05” diye görünür. Bu düzen AH ve AL'nin aynı yazmacın iki yarısı olduğunu açıkça gösterir.
- Bellek. Adres sütunu fiziksel adresleri gösterir: 0700:0100 = 07000h + 0100h = 07100h. Program baytları bu adresten başlar: B8, 05, 00, BB, 03 …
- Komut listesi. Bellekteki baytların komutlara geri çevrilmiş hâlidir. Vurgulu satır sıradaki komuttur, yani CS:IP'nin gösterdiği komut; az önce yürütülen değil. Liste sabitleri onaltılık ve 5 basamakla gösterir:
MOV AX, 00005h. - Ek pencereler. screen ekran çıktısını, vars değişkenleri, stack yığını, flags bayrakları ayrı pencerelerde gösterir.
Komut listesindeki vurgunun anlamı yeni başlayanları sık yanıltır. Şekildeki durumda vurgulu satır MOV BX, 00003h'tür, ama BX hâlâ 0000h'dir. Bu bir hata değildir: vurgulu komut henüz yürütülmemiştir. Bir sonraki single step onu yürütür; BX = 0003h olur ve vurgu ADD AX, BX satırına geçer. Yazmaç değerleri her zaman vurgulu satırdan önceki komutların sonucudur.
Öykünücüde bir programı incelemenin yöntemi basittir. Her single step'ten önce sıradaki komutun hangi yazmacı ve bayrağı nasıl değiştireceği tahmin edilir. Adım atılır ve tahmin pencerenin gösterdiği değerle karşılaştırılır. Bu notun izleme tabloları tam olarak bu tahminlerin yazılı hâlidir.
Bellek sütunundaki adresi bağıl konumla karıştırmak. Öykünücünün bellek sütunu 07100h gösterirken program 0100h'yi kullanır. 07100h fiziksel adrestir; 0100h ise CS = 0700h kesimi içindeki bağıl konumdur. MOV AL, [0100h] komutu 07100h'deki baytı okur, 00100h'dekini değil. Aradaki ilişki her zaman kesim × 10h + bağıl konumdur.
3.2.6Yazım kuralları
Assembler sayıları, karakterleri ve adları yazılışlarından tanır. Kurallar azdır, ama birinin unutulması ya bir derleme hatası ya da fark edilmesi zor bir yanlış değer üretir.
Sayı tabanları. Bir sayının tabanı sonuna eklenen harfle belirtilir. Harf yoksa sayı onluktur. Tablo 3.2.18 aynı değeri, 25'i, dört tabanda verir. Assembler hepsini aynı bayta, 19h'ye çevirir; MOV AL, … satırlarının hepsi B0 19 olur.
| Taban | Sonek | Yazılış | MOV AL, … kodu |
|---|---|---|---|
| onluk | yok ya da d | 25, 25d | B0 19 |
| onaltılık | h | 19h | B0 19 |
| ikili | b | 00011001b | B0 19 |
| sekizli | o | 31o | B0 19 |
Taban seçimi yalnız okunabilirlik içindir; işlemci farkı görmez. Bir port maskesi ya da bayrak deseni ikili yazıldığında hangi bitin kurulduğu hemen anlaşılır: 00100000b bit 5'tir. Bir adres ise onaltılık yazılır, çünkü kesim ve bağıl konum hesapları onaltılıkta yapılır. Döngü sayıları ve günlük büyüklükler onluk yazılır.
Harfle başlayan onaltılık sayılar. Onaltılık rakamlar A–F harflerini içerir. FFh yazıldığında assembler bunun bir sayı mı yoksa FFh adlı bir etiket mi olduğunu ayırt edemez; kurala göre harfle başlayan her dizi bir addır. Bu yüzden harfle başlayan onaltılık sayıların önüne 0 konur: 0FFh, 0B800h. Baştaki sıfır değeri değiştirmez, yalnız dizinin bir sayı olduğunu bildirir. MOV AX, 0B800h komutu B8 00 B8 olarak kodlanır.
Karakterler. Tırnak içindeki bir karakter, ASCII kodunun yerine geçer. 'A' = 41h olduğundan MOV CL, 'A' ile MOV CL, 41h aynı makine kodunu üretir: B1 41. Karakter yazımı, kodu ezberleme yükünü kaldırır ve programın ne yaptığını açıkça gösterir. Ekrana bir rakam yazdıran program ADD DL, '0' yazdığında 0–9 arası bir değeri '0'–'9' karakterine çevirdiği hemen anlaşılır.
İşaretli sayılar. Eksi işaretli bir sabit ikiye tümleyen olarak saklanır. -1 8 bitte FFh, 16 bitte FFFFh olur: MOV AL, -1 = B0 FF, MOV AX, -1 = B8 FF FF. 8 bitlik bir yazmaca yazılabilecek sabitler −128 ile 255 arasındadır: negatif değerler işaretli, büyük pozitif değerler işaretsiz yorumla sığar. MOV AL, 256 ya da MOV AL, -129 hata verir.
Büyük-küçük harf. Assembler duyarsızdır: mov, MOV, Mov aynıdır; var1 ile VAR1 aynı addır. Okunabilirlik için tutarlı bir düzen seçilir. Bu notta komutlar ve yazmaçlar büyük, değişken ve etiket adları küçük harfle yazılmıştır.
Açıklamalar. ; işaretinden sonrası açıklamadır. Assembly'de neredeyse her satıra açıklama yazılır, çünkü komutların kendisi amacı anlatmaz. İyi alışkanlık, açıklamaya komutun “ne” yaptığını değil “neden” yapıldığını yazmaktır. INC SI ; SI = SI + 1 bilgi vermez; INC SI ; dizinin sonraki elemanı verir.
Sonek unutmak. MOV AL, 10 ile MOV AL, 10h farklı değerlerdir: 10 ve 16. Onaltılık bir değeri soneksiz yazmak assembler'ın hata vermeyeceği, ama programın yanlış çalışacağı bir hatadır. Ekran belleğinin kesimi B800h'yi MOV AX, B800 diye yazan programcı ise hem soneki hem baştaki sıfırı unutmuş olur; assembler B800'ü tanımsız bir ad sayar.
3.2.7Hatalar
3.2.7.1MOV'un işlenen kısıtları
MOV en sık kullanılan komuttur ve en sık hata da onunla yapılır. Hataların neredeyse hepsi, 8086'nın komut kodlamasında var olmayan bir işlenen birleşimini yazmaktan gelir. Tablo 3.2.19 en yaygın altısını verir.
| Hatalı | Neden? | Doğrusu |
|---|---|---|
MOV AL, BX | boyutlar farklı (8 ↔ 16 bit) | MOV AL, BL ya da MOV AX, BX |
MOV DS, 1234h | kesim yazmacına sabit atanamaz | MOV AX, 1234h · MOV DS, AX |
MOV AL, [AX] | adreslemede yalnız BX, SI, DI, BP | MOV BX, AX · MOV AL, [BX] |
MOV AL, FFh | FFh bir ad sanılır | MOV AL, 0FFh |
MOV IP, 200h | IP'ye MOV ile yazılamaz | JMP ile atlamak |
MOV AL, 300 | 300 > 255, 8 bite sığmaz | MOV AX, 300 |
Boyut uyuşmazlığı. MOV'un iki işleneni aynı genişlikte olmalıdır, çünkü işlem kodu tek bir genişlik biti taşır: ya 8 bit ya 16 bit. MOV AL, BX komutunda 16 bitlik bir değerin hangi yarısının alınacağı belirsizdir. Programcı alt baytı istiyorsa MOV AL, BL yazar. Tersi yöndeki MOV CX, AL de aynı nedenle hatalıdır; 8 bitlik bir değeri 16 bite genişletmek için üst yarı ayrıca kurulur: MOV CL, AL ve MOV CH, 0.
Kesim yazmacına sabit. 8086'da kesim yazmacına yazan MOV yalnız genel yazmaçtan ya da bellekten okur. Anlık değer yükleyen bir biçimi yoktur. Bu yüzden ekran belleğine erişmek için kesim kurmak iki satır ister: MOV AX, 0B800h ve MOV DS, AX.
Adres yazmacı. 8086'da köşeli ayraç içinde yalnız BX, BP, SI ve DI kullanılabilir. Bunun nedeni ModR/M baytının R/M alanıdır: bellek modlarında bu üç bit yalnız bu dört yazmacın belirli birleşimlerini kodlar. AX'i adres olarak kullanmanın bir kodu yoktur.
IP'ye yazmak. IP hiçbir veri komutunun işleneni olamaz. IP'yi değiştirmenin tek yolu akış komutlarıdır: JMP, Jcc, CALL, RET, INT ve IRET. Assembler IP'yi yazmaç adı olarak tanımaz; satırı “hedef sabit olamaz” ya da “tanımsız ad” hatasıyla reddeder.
Sığmayan sabit. 8 bitlik bir yazmaç en çok 255'i (işaretli yorumda −128'i) tutar. 300 dokuz bit ister. Assembler satırı reddeder; değer 16 bitlik bir yazmaca yazılır.
3.2.7.2Öteki söz dizimi hataları
| Hatalı | Neden? | Doğrusu |
|---|---|---|
MOV CS, AX | CS yalnız JMP, CALL, RET, INT ile değişir | uzak atlama |
MOV ES, DS | kesimden kesime MOV yok | MOV AX, DS · MOV ES, AX |
MOV [BX], [SI] | iki bellek işleneni | MOV AL, [SI] · MOV [BX], AL |
INC [BX] | boyut belirsiz | INC BYTE PTR [BX] |
MOV AL, [BX+BP] | iki taban yazmacı birlikte olmaz | [BX+SI] ya da [BP+DI] |
ADD 5, AX | hedef sabit olamaz | ADD AX, 5 |
PUSH 5 | 80186'dan önce yok | MOV AX, 5 · PUSH AX |
SHL AX, 2 | 8086'da sayı yalnız 1 ya da CL | MOV CL, 2 · SHL AX, CL |
CS'ye yazmak. CS'yi MOV ile değiştirmek, kodun ortasında başka bir kesime geçmek demektir; ama IP aynı kalır ve işlemci rastgele bir adresten devam eder. CS ile IP'nin birlikte değişmesi gerekir. Bunu uzak JMP, uzak CALL, uzak RET, INT ve IRET yapar.
Kesimden kesime. İki kesim yazmacı arasında doğrudan aktarım yoktur. Değer bir genel yazmaç üzerinden iki adımda taşınır. Bellekten belleğe aktarım da aynı biçimde yapılır: bir komutta en çok bir bellek işleneni bulunur, değer önce bir yazmaca alınır.
Boyut belirsizliği. INC [BX] satırında işlenenin bir bayt mı bir sözcük mü olduğu belli değildir; hiçbir işlenen bir yazmaç değildir ki boyut ondan çıkarılsın. Assembler bu yüzden boyutun açıkça yazılmasını ister: INC BYTE PTR [BX] ya da INC WORD PTR [BX]. Aynı kural MOV [BX], 5 için de geçerlidir. emu8086 b.[bx] ve w.[bx] kısaltmalarını da kabul eder.
Adres birleşimleri. 8086'nın kabul ettiği adres biçimleri bir taban yazmacı (BX ya da BP), bir indis yazmacı (SI ya da DI) ve bir sabitin birleşimidir. İki taban ([BX+BP]) ya da iki indis ([SI+DI]) birlikte kullanılamaz; ModR/M baytında bunların kodu yoktur.
Sonraki işlemcilerin komutları. PUSH 5 ve SHL AX, 2 80186 ile geldi. MASM 8086 için derlerken bu satırlarda hata verir. emu8086 ise bu biçimleri kabul eder; derlenen kod öykünücüde çalışır, ama gerçek bir 8086'da işlemci bu baytları tanımaz. 8086 için yazılan bir programda sabit yığına bir yazmaç üzerinden itilir, çok bitli kaydırmada sayı CL'ye konur.
sozcuk DW 1234h ve bayt DB 5 tanımlı. MOV sozcuk, bayt satırı neden hatalıdır ve nasıl düzeltilir?
Satırda iki hata birden vardır. İki işlenen de bellektir ve boyutları farklıdır (16 ↔ 8 bit). Değer bir yazmaç üzerinden taşınır ve üst bayt ayrıca sıfırlanır:
MOV AL, bayt ; AL = 05h
MOV AH, 0 ; AX = 0005h
MOV sozcuk, AX ; sozcuk = 0005hbayt işaretli bir sayı olsaydı ikinci satır yerine CBW kullanılırdı.
3.2.7.3Derleme hatası ve mantık hatası
Bir assembly programında iki tür hata bulunur. Ayrımı bilmek, hatanın nasıl aranacağını belirler.
Derleme hatası (söz dizimi hatası), assembler'ın kaynağı çevirirken bulduğu hatadır. Assembler satır numarasını ve nedeni bildirir; program hiç oluşmaz. Mantık hatası ise programın derlenip çalıştığı, ama yanlış sonuç verdiği durumdur. Assembler bunu bilemez, çünkü her satır kendi başına geçerlidir.
| Derleme hatası | Mantık hatası |
|---|---|
MOV AL, BX: boyut uyuşmazlığı | RET'i unutmak: veri komut sanılır |
JMP bsla: tanımsız etiket | işaretli sayı için JA kullanmak |
MOV AL, 300: sığmayan sabit | ADC yerine ADD: elde kaybolur |
MOV DS, 1234h: kesime sabit | .EXE programında DS'yi yüklememek |
Derleme hatası kolay hatadır: assembler yerini gösterir, düzeltme çoğunlukla tek satırdır. Mantık hatası ise sessizdir. Program çalışır, belki çoğu girdi için doğru sonuç verir, yalnız bazı durumlarda yanılır. Tablodaki örnekler bu türün tipik hâlleridir. JA işaretsiz karşılaştırmanın atlamasıdır; −1 ile 1 karşılaştırılırken −1'i FFFFh, yani büyük bir sayı sayar. ADD ile yapılan çok baytlı toplama, düşük baytlardan gelen eldeyi yüksek baytlara aktarmaz. .EXE programında DS yüklenmezse değişkenler PSP'nin bulunduğu kesimde aranır ve bambaşka baytlar okunur.
Mantık hatasını bulmanın yolu tek adım çalıştırmadır. Program öykünücüde komut komut ilerletilir. Her adımdan önce beklenen yazmaç ve bayrak değerleri hesaplanır, adımdan sonra pencerede görünenle karşılaştırılır. Değerlerin ilk ayrıldığı komut, hatanın bulunduğu yerdir. Hata bu komutun kendisinde olabilir. Komut doğru da olabilir; o zaman daha önceki bir satır ona yanlış bir değer bırakmıştır. emu8086'nın step back düğmesi bu aramayı kolaylaştırır: hatalı değer görülünce birkaç adım geri gidilip değerin nereden geldiği izlenir.
Bir öğrenci AL'deki sayıyı 3 ile çarpıp sonucu AX'te istiyor ve şu kodu yazıyor: MOV BL, 3 · MUL BL. Program AL = 7 için AX = 0015h, yani 21 veriyor. Aynı kod bir başka yerde AH = 12h iken çalışınca öğrenci AH'nin neden silindiğini soruyor. Bu bir hata mı?
Kod doğrudur; yanılgı beklentidedir. MUL'ün sonucu örtük olarak AX'in tamamına yazılır: 7 × 3 = 21 = 0015h, AH = 00h. AH'deki 12h'nin korunması beklentisi bir mantık hatasıdır, ama hata kodda değil, programın AH'yi saklayacağı varsayımındadır. AH'deki değer gerekiyorsa MUL'den önce başka bir yazmaca alınır. Tek adım çalıştırma bu durumu hemen gösterir: MUL adımından sonra AH sütunu 12'den 00'a döner.
Programı bir bütün olarak çalıştırıp yalnız sonuca bakmak. Yanlış sonuç veren bir programı run ile çalıştırıp yeniden yazmaya başlamak, hatayı başka bir yere taşır. Önce tek adımla ilerlenir ve ilk sapma bulunur. Uzun bir döngüde tek adım sıkıcıysa döngüden önceki ve sonraki durum karşılaştırılarak hata önce bir bölgeye, sonra bir satıra daraltılır.
3.2.8Alıştırmalar ve çözümleri
Sunumdaki altı alıştırma aşağıda ara adımlarıyla çözülmüştür. Bütün yazmaç ve bayrak değerleri öykünücüde çalıştırılarak denetlenmiştir.
AX = 0ABCDh iken MOV AH, 0 sonrası AX, AL ve BX değerleri nedir?
AX = ABCDh'nin yüksek yarısı AH = ABh, düşük yarısı AL = CDh'dir. MOV AH, 0 yalnız AH'ye yazar: AH = 00h. AL dokunulmadan kalır. Sonuç AX = 00CDh, AL = CDh olur. BX komutta ne yazılı ne örtük olarak geçer; değeri ne ise o kalır. Bu komut, işaretsiz bir 8 bitlik değeri 16 bite genişletmenin en kısa yoludur.
AX = 1234h, BL = 03h iken MUL BL sonrası AX kaçtır? AH'deki 12h'ye ne olur?
8 bitlik MUL'de çarpılan AX değil, örtük olarak AL'dir: AL = 34h = 52. 52 × 3 = 156 = 009Ch. Sonuç örtük olarak AX'in tamamına yazılır; AH = 00h, AL = 9Ch olur. AH'deki 12h silinir. Üst yarı sıfır olduğu için CF = OF = 0'dır. AX'in tamamının 3 ile çarpıldığını düşünen biri 1234h × 3 = 369Ch bulur; bu sonuç için MUL BX gerekir ve sonuç DX:AX'e yazılır.
8 MHz'lik bir 8086'da 2000 kez dönen bir döngüde sayaç INC sayac (21 tur) yerine INC CX (2 tur) ile artırılırsa kaç saat turu ve kaç milisaniye kazanılır?
Her turda kazanç 21 − 2 = 19 saat turudur. 2000 turda 2000 × 19 = 38 000 saat turu kazanılır. 8 MHz'de bir saat turu 1 / (8 × 106) s = 0,125 µs'dir. Kazanç 38 000 × 0,125 µs = 4750 µs = 4,75 ms olur.
AL = 80h iken ADD AL, 80h sonrası AL, CF, ZF, SF ve OF ne olur?
80h + 80h = 100h. Sonuç dokuz bit ister; AL'ye alt sekiz bit yazılır: AL = 00h. Dokuzuncu bit CF'ye gider: CF = 1. Sonuç sıfırdır: ZF = 1. En üst bit 0'dır: SF = 0. İşaretli yorumda 80h = −128'dir ve −128 + (−128) = −256 sekiz bitlik aralığa (−128 … 127) sığmaz: OF = 1. Ayrıca 00h'nin bir bitleri çift sayıda olduğu için PF = 1, bit 3'ten elde olmadığı için AF = 0'dır.
Program 0100h'de başlıyor: 3 + 2 + 1 + 4 baytlık dört komut yürütülünce IP ne olur?
Atlama olmadığı için IP her komutta uzunluğu kadar ilerler: 0100h → 0103h → 0105h → 0106h → 010Ah. Toplam 10 bayt = 0Ah olduğundan IP = 0100h + 0Ah = 010Ah olur.
MOV CX, AL ve MOV ES, 0B800h neden hatalıdır? Doğru yazılışları nedir?
MOV CX, AL: işlenenler farklı boyuttadır (16 ↔ 8 bit). Amaç yalnız alt baytı kopyalamaksa MOV CL, AL yazılır. AL'nin değeri CX'in tamamında işaretsiz olarak istenirse üst yarı da sıfırlanır: MOV CL, AL · MOV CH, 0.
MOV ES, 0B800h: kesim yazmacına anlık değer yüklenemez. Değer bir genel yazmaç üzerinden taşınır: MOV AX, 0B800h · MOV ES, AX.
3.2.9Özet
- Assembly dili makine koduyla birebir eşleşen düşük seviyeli bir dildir. Her komut satırı tek bir makine komutuna çevrilir:
MOV AX, 5=B8 05 00. Küçük ve hızlı kod üretir, donanıma doğrudan erişir, ama taşınabilir değildir. - Assembler anımsatıcıları işlem kodlarına, adları adreslere çevirir. emu8086 düzenleyici, assembler ve öykünücüyü birleştirir; yazmaçları, belleği ve bayrakları adım adım gösterir.
- Satır yapısı
[etiket:] komut hedef, kaynak ; açıklamabiçimindedir. Hedef soldadır; kaynak değişmez. Assembler büyük-küçük harfe duyarsızdır; açıklamalar makine koduna girmez. - Direktifler (ORG, EQU, END) makine komutu üretmez; assembler'a bilgi verir. DB ve DW yalnız veri baytı üretir. Makro çağrısı birden çok komutun yerine geçer.
- Ad harfle ya da alt çizgiyle başlar; ayrılmış sözcükler ad olamaz. Kod etiketi iki nokta ile biter ve bir adresi gösterir; değişken adı adres ile türü birlikte taşır.
- İşlenen türleri: yazmaç (en hızlı), anlık değer (yalnız kaynak), bellek (yol döngüsü ister, komutta en çok bir tane). İki işlenen aynı boyutta olmalıdır.
- Örtük işlenenler komutta yazılmaz ama değişir: MUL AX'e, DIV AL ile AH'ye yazar; LOOP CX'i azaltır; CBW AH'yi doldurur; PUSH SP'yi değiştirir.
- Bellek erişimi en az dört T durumluk bir yol döngüsüdür. Bellek işlenenli komutlar etkin adres süresiyle birlikte yazmaç eşlerinden birkaç kat uzundur:
INC CX2,INC sayac21 tur. - IP sıradaki komutun bağıl konumudur ve komut uzunluğu kadar ilerler. Yalnız akış komutları IP'ye yeni değer yazar.
- MOV, XCHG, LEA, PUSH, POP, NOT ve LOOP bayrakları değiştirmez. INC ve DEC CF'ye dokunmaz. ADD, SUB ve CMP altı durum bayrağını yeniden yazar. MUL sonrası ZF, SF, AF, PF tanımsızdır.
- .COM programı
ORG 100hile 0100h'den başlar; ilk 256 bayt PSP'dir. Başlangıçta CS = DS = ES = SS, IP = 0100h, SP = FFFEh'dir. RET yığındaki 0000h ile PSP'dekiINT 20h'ye döner. Veriler RET'ten sonra durur. - Bellekte komut ile veri arasında işaret yoktur; bir baytın anlamını programın akışı belirler. Aynı komutun birden çok geçerli kodlaması olabilir.
- Derleme hatasını assembler bulur; mantık hatası ancak tek adım çalıştırıp beklenen değerleri öykünücüdekiyle karşılaştırarak bulunur.
3.2.10Kavram listesi
Terimlerin İngilizce karşılıkları ve öteki bölümlerdeki kullanımları terim sözlüğünde bulunur.
- assembly (assembly dili) assembly language
- anımsatıcı mnemonic
- komut instruction
- işlem kodu opcode
- işlenen operand
- örtük işlenen implicit operand
- anlık değer immediate value
- açıklama comment
- etiket label
- değişken variable
- direktif directive
- sabit (EQU) constant
- konum sayacı ($) location counter
- makro macro
- assembler assembler
- öykünücü emulator
- .COM programı .COM program
- PSP (program kesimi öneki) program segment prefix
- akümülatör accumulator
- sayaç yazmacı counter register
- yol döngüsü bus cycle
- T durumu T state
- saat turu (tur) clock cycle
- etkin adres (EA) effective address
- komut işaretçisi (IP) instruction pointer
- bayrak yazmacı (FLAGS) flags register
- ModR/M baytı ModR/M byte
- little-endian little-endian
- tek adım single-step
- derleme hatası / mantık hatası syntax error / logic error
3.2.11Kendini Dene
STC,MOV AX, 0FFFFh,INC AXkomutları sırayla çalışıyor. Sonunda AX, CF ve ZF kaçtır?Cevap
FFFFh + 1 = 10000h, 16 bite sığmaz ve AX = 0000h olur. Sonuç sıfırdır: ZF = 1. INC CF'ye dokunmaz; CF, STC'den kalan 1'dir. MOV da bayrak değiştirmediği için CF = 1 hiç bozulmamıştır. Aynı toplama
ADD AX, 1ile yapılsaydı CF yine 1 olurdu, ama bu kez taşan eldeden dolayı.ORG 100hile başlayan bir programda sıraylaMOV AL, 5,MOV BX, 1234h,INC BX,RETveveri DB 9satırları var. Programın baytları nelerdir,veri'nin bağıl konumu nedir?Cevap
MOV AL, 5=B0 05(0100h),MOV BX, 1234h=BB 34 12(0102h),INC BX=43(0105h; 40h + 3),RET=C3(0106h),veri=09(0107h). Komutlar 2 + 3 + 1 + 1 = 7 bayttır;veri0100h + 7 = 0107h'dedir. Program toplam 8 bayttır ve sonunda BX = 1235h olur.MOV AX, [BX+SI]veADD [BX], AXkomutları 5 MHz'lik bir 8086'da en iyi durumda kaç saat turu ve kaç mikrosaniye sürer? (Yazmaçtan belleğe okuma 8 + EA, belleğe toplama 16 + EA tur.)Cevap
[BX+SI]için EA = 7 tur: MOV 8 + 7 = 15 tur.[BX]için EA = 5 tur: ADD 16 + 5 = 21 tur. Toplam 36 tur; 5 MHz'de 36 × 0,2 µs = 7,2 µs. ADD'in uzun sürmesinin nedeni belleğe hem okuma hem yazma yapmasıdır: iki yol döngüsü.AX = 25 iken
MOV BL, 4veDIV BLçalışıyor. AL, AH ve AX kaçtır?Cevap
Bölünen örtük olarak AX = 25'tir. 25 ÷ 4 = 6, kalan 1. Bölüm AL'ye, kalan AH'ye yazılır: AL = 06h, AH = 01h, AX = 0106h. AX'i bir sayı olarak okuyan biri 262 görür; DIV'den sonra AX'in iki yarısı ayrı anlam taşır.
Şu programın kaç satırı bayt üretir, program kaç bayttır?
ORG 100h·k EQU 5·MOV AX, 5·MOV BX, k·MOV AL, sayi·RET·sayi DB 0·END.MOV AL, sayisatırının baytları nedir?Cevap
ORG, EQU ve END bayt üretmez. Üç MOV 3'er bayt, RET 1 bayt, DB 1 bayt: beş satır, 11 bayt.
sayi0100h + 10 = 010Ah'dedir.MOV AL, sayiAL'ye doğrudan adresten okuyan akümülatör biçimidir:A0 0A 01.MOV AL, 0F0h,ADD AL, 20h,MOV BL, AL,NOT BLçalışıyor. Sonunda AL, BL, CF ve ZF kaçtır?Cevap
F0h + 20h = 110h: AL = 10h, CF = 1, ZF = 0. MOV ile BL = 10h olur; bayraklar değişmez. NOT BL = EFh; NOT da bayrak değiştirmez. Sonuç AL = 10h, BL = EFh, CF = 1, ZF = 0. Bayraklar ADD'in bıraktığı gibidir.
emu8086'da şablon programda (
MOV AX, 5,MOV BX, 3,ADD AX, BX,MOV CL, AL,RET) üç kez single step'e basılıyor. Komut listesinde hangi satır vurgulu, IP ve AX kaçtır? Bellek sütununda bu komutun ilk baytı hangi fiziksel adreste görünür?Cevap
Üç komut yürütülmüştür: AX = 0008h, BX = 0003h. IP = 0100h + 3 + 3 + 2 = 0108h. Vurgulu satır sıradaki komut olan
MOV CL, AL'dir; CL henüz 00h'dir. Fiziksel adres 07000h + 0108h = 07108h; orada8Abaytı görünür.MOV DX, 0AhveINC CXkomutlarının makine kodları nedir? İkisi ardışık olarak 0103h'den başlıyorsa sonraki komut hangi adresten başlar?Cevap
DX'in yazmaç numarası 2'dir.
MOV DX, 0Ah= B8h + 2 = BAh ve sabit düşük bayt önce:BA 0A 00(3 bayt).INC CX= 40h + 1 =41(1 bayt). İki komut 4 bayttır; sonraki komut 0103h + 4 = 0107h'den başlar.Bir program
MOV CL, 3ile kaydırma sayısını kuruyor, ardındanMOV CX, 10ile bir döngü sayacı kuruyor ve en sondaSHL AX, CLyazıyor. Program derlenir mi? AX kaç bit kayar?Cevap
Program derlenir; her satır geçerlidir. Ancak CL, CX'in alt yarısıdır.
MOV CX, 10CL'yi 0Ah yapar ve kaydırma 3 değil 10 bit olur. Bu bir mantık hatasıdır. Kaydırma sayısı CL'ye, kaydırmadan hemen önce yazılmalıdır.
3.2.12İleri okuma
- emu8086 belgeleri, 8086 assembler tutorial for beginners: sayı sistemleri, bellek erişimi, değişkenler ve komut kümesi başvurusu; emu8086 söz dizimine en yakın kaynaktır.
- B. B. Brey, The Intel Microprocessors (8. baskı), Bölüm 4 ve 6: veri taşıma komutları, ModR/M kodlaması, .COM ve .EXE programlarının yapısı.
- M. A. Mazidi, J. G. Mazidi, The 80x86 IBM PC and Compatible Computers, Bölüm 1–2: assembly programının yapısı, direktifler, örnek programlar ve hata ayıklayıcıyla çalışma.
- Intel, 8086 16-Bit HMOS Microprocessor veri sayfası: yol döngüsünün T durumları ve komut süreleri tablosu.
3.2.13Kaynaklar
- emu8086 belgeleri, 8086 assembler tutorial for beginners (bölüm 1: numbering systems, bölüm 2: memory access).
- Intel, 8086 16-Bit HMOS Microprocessor veri sayfası.
- B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson.
- M. A. Mazidi, J. G. Mazidi, The 80x86 IBM PC and Compatible Computers, Pearson.
İlgili sayfalar: Bölüm 3.2 sunumu · Çalışma soruları · Terim sözlüğü · © Sercan Külcü. Tüm hakları saklıdır.