Mikroişlemciler · Ders Notu

Bölüm 1.2: Sayı Sistemleri

Bir mikroişlemcinin içindeki her şey bitlerden oluşur: yazmaçlar, bellek hücreleri, adres ve veri yolundaki hatlar, bayraklar. Bir yazmaçta duran 1111 1011 deseni bağlama göre 251 olabilir, −5 olabilir, bir karakterin parçası ya da bir kayan noktalı sayının üs alanı olabilir. Desenin kendisi anlam taşımaz; anlamı programcının seçtiği gösterim verir. Bu not, 8086 programlamaya geçmeden önce gereken sayı gösterimlerini toplar. Konumsal sayı sistemleriyle başlar, tabanlar arası dönüşümü hem elle hem 8086 komutlarıyla yapar. Ardından negatif sayıların ikiye tümleyen gösterimini, ikili ve onaltılık aritmetiği, elde ile işaretli taşma arasındaki farkı inceler. Son kesimler bitin donanımdaki karşılığını (gerilim düzeyleri, flip-flop), IEEE 754 kayan nokta biçimini, BCD'yi, bayt sıralamasını ve Gray kodunu anlatır.

Öğrenme çıktıları

Konumsal sistemleri okumak
Onluk, ikili ve onaltılık bir sayının değerini basamak ağırlıklarıyla hesaplamak; bit, nibble, bayt ve sözcük birimlerinin aralığını söylemek; assembly'deki b, h, o soneklerini doğru kullanmak.
Tabanlar arasında dönüştürmek
Onluk sayıyı bölme-kalan yöntemiyle, kesirli kısmı 2 ile çarpma yöntemiyle çevirmek; ikili ile onaltılık arasında dörtlü gruplamayla geçmek; aynı işi DIV ve SHR komutlarıyla yapan programları izlemek.
İşaretli sayıları kullanmak
Negatif sayıları ikiye tümleyen gösterimiyle yazmak; birler tümleyeni ve işaret-büyüklük gösterimiyle karşılaştırmak; 8 ve 16 bitlik işaretli aralıkları, işaret genişletmeyi ve sabit noktalı kesirleri açıklamak.
Aritmetik yapmak ve bayrakları yorumlamak
İkili ve onaltılık toplama ve çıkarma yapmak; çıkarmayı tümleyenle toplamaya çevirmek; bir işlemden sonra CF ve OF bayraklarının değerini gerekçesiyle bulmak.
Kodlamaları çözmek
32 bitlik bir IEEE 754 desenini çözmek ve kodlamak; BCD toplamayı düzeltmeyle yapmak; çok baytlı bir değerin little-endian bellek düzenini yazmak; Gray kodunu üretmek ve geri çevirmek.
Biti donanıma bağlamak
Gerilim düzeylerinin bitlere nasıl karşılık geldiğini, flip-flop türlerinin davranışını ve bir yazmacın D flip-flop'lardan nasıl kurulduğunu açıklamak.

1.2.1Sayıları temsil etmek

Sayı soyut bir kavramdır. Beş elma, beş parmak ve beş gün aynı niceliği paylaşır; ama bu niceliği kâğıda, taşa ya da bir devreye yazmak için bir gösterim gerekir. Gösterim seçimi, sayıyla yapılacak işlerin ne kadar kolay olacağını belirler. Bu kesim, konumsal sistemlerin neden bugünkü biçimini aldığını iki eski gösterim üzerinden açıklar.

1.2.1.1Sopadan simgeye

İnsanlar saymak için önce somut nesneler kullandı: çakıl taşları, düğümler, sopalar. Sopalarla sayan biri beşi | | | | | diye gösterir. Bu gösterimin bir üstünlüğü vardır: değer, simge sayısına eşittir ve hiçbir kural bilmeden okunur. Sakıncası da açıktır. Yüz için yüz çizgi gerekir. İki sayıyı karşılaştırmak için çizgileri tek tek saymak gerekir.

Roma İmparatorluğu'nda bu soruna kısmi bir çözüm bulundu. Küçük sayılar hâlâ çizgiyle yazıldı (III üçtür), ama belirli öbekler için ayrı simgeler kullanıldı: V beş sopayı, X on sopayı temsil etti. Bugün kullandığımız gösterim ise bambaşka bir fikre dayanır: bir rakamın değeri yalnız rakamın kendisine değil, sayının içindeki konumuna da bağlıdır. 754'teki 7 yedi değil, yedi yüzdür. Şekil 1.2.1 üç gösterimi yan yana koyar.

5 sopaIII = 3VV = 5XX = 10754konumsal: 7·100 + 5·10 + 4
Şekil 1.2.1: Aynı fikrin üç gösterimi. Solda beş sopa, ortada Romen simgeleri (III = 3, V = 5, X = 10), sağda konumsal onluk gösterim: 754 = 7·100 + 5·10 + 4.

1.2.1.2Romen rakamları

Romen sisteminde yedi simge vardır. Tablo 1.2.1 bunları değerleriyle verir. Sayı, simgelerin değerleri toplanarak ve gerektiğinde çıkarılarak okunur.

Tablo 1.2.1: Romen simgeleri ve değerleri.
SimgeIVXLCDM
Değer1510501005001000
Tanım 1.2.1

Romen rakamları toplama ve çıkarma kuralıyla okunur. Büyük bir simgeden sonra gelen küçük simge eklenir: VI = 5 + 1 = 6. Büyük bir simgeden önce gelen küçük simge çıkarılır: IV = 5 − 1 = 4. Çıkarma yalnız altı çiftte kullanılır: IV (4), IX (9), XL (40), XC (90), CD (400) ve CM (900).

Okumanın güvenli yolu, sayıyı soldan sağa değer öbeklerine ayırmaktır. Her öbek ya tek başına toplanan simgelerden ya da altı çıkarma çiftinden biridir. Öbeklerin değerleri bulunur ve toplanır.

Örnek 1.2.1

MCMLXXXVI sayısını okuyalım. Soldan sağa öbekler M, CM, LXXX ve VI'dır. M = 1000'dir. CM bir çıkarma çiftidir: C, M'den önce geldiği için 1000 − 100 = 900 eder. LXXX = 50 + 10 + 10 + 10 = 80'dir. VI = 5 + 1 = 6'dır. Toplam 1000 + 900 + 80 + 6 = 1986 olur.

MMVII için öbekler M, M ve VII'dir: 1000 + 1000 + 7 = 2007. Bir eksik I ile yazılan MMVI ise 2006'dır.

M1000+CM900+LXXX80+VI6= 1986
Şekil 1.2.2: MCMLXXXVI'nın öbeklere ayrılması: M = 1000, CM = 900, LXXX = 80, VI = 6; toplam 1986.

Romen sisteminin iki eksiği vardır ve ikisi de aritmetiği zorlaştırır. Birincisi, sıfır için bir simge yoktur. İkincisi, basamak kavramı yoktur: X her yerde ondur. Bu yüzden iki Romen sayısını alt alta yazıp sütun sütun toplamak mümkün olmaz. MCMLXXXVI ile MMVII'yi toplamak için önce ikisini de değerlerine çevirmek gerekir. Çarpma ve bölme daha da zahmetlidir. Konumsal sistem bu iki eksiği birlikte giderir.

Sık yapılan hata

Çıkarma kuralını her küçük-büyük çiftine uygulamak. IC 99 değildir; 99, XCIX (90 + 9) diye yazılır. MCMXLIV okunurken XL'yi LX (60) gibi okumak da sık görülür: XL'de X, L'den önce geldiği için çıkarılır ve öbek 40 eder. Doğru okuma 1000 + 900 + 40 + 4 = 1944'tür.

1.2.2Konumsal sayı sistemleri

Konumsal sistemde her basamağın bir ağırlığı vardır ve rakam bu ağırlıkla çarpılır. Ağırlıklar tabanın kuvvetleridir. Onluk sistemde ağırlıklar 1, 10, 100, 1000 diye gider; ikili sistemde 1, 2, 4, 8 diye. Bu kesim üç tabanı (10, 2, 16) aynı formülle ele alır, bilgisayar dünyasının veri birimlerini tanımlar ve assembly'de sayıların nasıl yazıldığını gösterir.

1.2.2.1Onluk sistem ve genel formül

Gündelik hayatta kullandığımız sistem onluk (decimal) sistemdir. Tabanı 10'dur ve on rakamı vardır: 0, 1, 2, …, 9. 754 sayısında 4 birler basamağında, 5 onlar basamağında, 7 yüzler basamağındadır. Değer, her rakamın kendi basamak ağırlığıyla çarpımlarının toplamıdır: 7 × 100 + 5 × 10 + 4 × 1 = 754. Şekil 1.2.3 bu toplamı basamak basamak gösterir.

710²700510¹50410⁰4700 + 50 + 4 = 754
Şekil 1.2.3: 754'ün basamakları ve ağırlıkları. 7 × 10² = 700, 5 × 10¹ = 50, 4 × 10⁰ = 4; toplam 754.
Tanım 1.2.2

Konumsal sayı sistemi (positional number system), rakamın değerinin bulunduğu basamağa göre belirlendiği sistemdir. b tabanında (base, radix) yazılmış n basamaklı dn−1 … d1 d0 sayısının değeri

N = dn−1 × bn−1 + … + d1 × b1 + d0 × b0 = Σi=0..n−1 di × bi

ifadesidir. Burada her di rakamı 0 ile b − 1 arasındadır; i basamağın konumudur ve sağdan 0'dan başlayarak sayılır.

Formül her taban için aynıdır; değişen yalnız b'dir. Bu yüzden ikili ve onaltılık sayılar için yeni bir kural öğrenmek gerekmez. Rakam kümesi tabana göre değişir: 10 tabanında on rakam, 2 tabanında iki rakam, 16 tabanında on altı rakam vardır. Bir rakamın tabana eşit ya da tabandan büyük olması mümkün değildir. İkili bir sayıda 2 rakamı, onluk bir sayıda “10” diye tek bir rakam yoktur.

1.2.2.2Konumun önemi ve sıfır

754 ile 547 aynı üç rakamdan oluşur, ama değerleri çok farklıdır. 7 en sola konduğunda 700, en sağa konduğunda 7 değerini alır. Şekil 1.2.4 iki sayıyı yan yana gösterir. Romen sisteminde X her yerde on iken konumsal sistemde aynı rakam, konumuna göre 700, 70 ya da 7 değerini alır.

710²700510¹50410⁰4754510²500410¹40710⁰7547
Şekil 1.2.4: Aynı rakamlar, farklı konumlar: 754 = 700 + 50 + 4, 547 = 500 + 40 + 7.

En sağdaki basamak her tabanda “birler” basamağıdır. Bunun nedeni, sıfırdan farklı her sayının sıfırıncı kuvvetinin 1 olmasıdır: x0 = 1. Matematikte 00 belirsiz kabul edilir; sayı sistemlerinde ve polinomlarda ise uzlaşım olarak 1 alınır. Taban hiçbir zaman 0 olmadığı için bu ayrıntı pratikte bir sorun yaratmaz.

Konumsal sistemin işlemesi için sıfır rakamı zorunludur. 705 sayısında onlar basamağı boştur. Bu boşluk bir sıfırla doldurulmazsa 705 ile 75 ayırt edilemez. Sıfır burada “hiçbir şey yok” anlamında bir yer tutucudur. Romen sisteminde sıfıra gerek yoktu, çünkü simgelerin değeri konumdan bağımsızdı.

1.2.2.3İkili sistem

Bilgisayarların onluk yerine ikili sistemi kullanmasının nedeni elektroniktir. Bir devre elemanını on farklı gerilim düzeyinden birinde tutmak ve bu düzeyleri gürültü altında birbirinden güvenle ayırmak zordur. İki durumlu bir eleman ise kolay yapılır. Bir transistör ya iletimdedir ya kesimdedir. Bir hat ya yüksek gerilimdedir ya düşük. Bir kondansatör ya yüklüdür ya boştur. Bu iki duruma 1 ve 0 adları verilir. Şekil 1.2.5 bir hattaki gerilimin zaman içinde 1 ve 0 değerlerini nasıl taşıdığını gösterir.

101100105 V0 Vyüksek = 1düşük = 0
Şekil 1.2.5: İkili sinyal. Yüksek gerilim (5 V) 1'i, düşük gerilim (0 V) 0'ı temsil eder; çizilen dizi 1011 0010'dır.
Tanım 1.2.3

İkili (binary) sistem, tabanı 2 olan konumsal sistemdir. Rakamları yalnız 0 ve 1'dir. Basamak ağırlıkları 2'nin kuvvetleridir: 20 = 1, 21 = 2, 22 = 4, 23 = 8, 24 = 16, 25 = 32, 26 = 64, 27 = 128, … İkili sayının her basamağına bit (binary digit) denir.

İkili sistem onluğa göre çok daha fazla basamak kullanır. 1000 sayısı onlukta dört basamaktır, ikilide on basamak gerektirir. Buna karşılık her basamağın yalnız iki değeri olduğu için aritmetik kuralları çok basittir. Toplama tablosu dört satırdan, çarpma tablosu da dört satırdan oluşur. Bu basitlik, bir toplayıcı devresini birkaç mantık kapısıyla kurmayı mümkün kılar.

1.2.2.4Bit, nibble, bayt ve sözcük

Bitler tek tek değil, sabit genişlikte öbekler hâlinde işlenir. Her öbek genişliğinin bir adı vardır. Şekil 1.2.6 32 bitlik bir değeri bu öbeklere ayırır; Tablo 1.2.2 her birimin aralığını ve 8086'daki karşılığını verir.

00010111000101110001011100010111bitnibble (4 bit)bayt (8 bit)sözcük (16 bit)çift sözcük (32 bit)yüksek bit (MSB) →← düşük bit (LSB)
Şekil 1.2.6: 32 bitlik bir değerin öbekleri: en sağdaki tek basamak bit, 4 bit nibble, 8 bit bayt, 16 bit sözcük, 32 bit çift sözcük. En soldaki bit en anlamlı bit (MSB), en sağdaki en az anlamlı bittir (LSB).
Tablo 1.2.2: Veri birimleri, işaretsiz aralıkları ve 8086'daki karşılıkları.
BirimBitİşaretsiz aralık8086'da
bit10 … 1bir bayrak (CF, ZF …)
nibble40 … 15 (0h … Fh)bir onaltılık rakam, bir BCD basamağı
bayt80 … 255AL, AH, BL …; DB
sözcük160 … 65 535AX, BX, CX, DX …; DW
çift sözcük320 … 4 294 967 295DX:AX çifti; DD

Tablonun üçüncü sütunu tek bir kuraldan çıkar: n bit ile 2n farklı desen yazılabilir. Desenler 0'dan başlayarak sayıldığında en büyük değer 2n − 1 olur. 8 bit için 28 = 256 desen vardır ve en büyük değer 255'tir. 16 bit için 65 536 desen vardır ve en büyük değer 65 535'tir. Bu sınırlar 8086 programlamada sürekli karşımıza çıkar. Bir bayta 256 yazılamaz; bir sözcüğe 70 000 yazılamaz.

Tanım 1.2.4

Nibble 4 bitlik öbektir. Bayt (byte) 8 bitlik öbektir ve belleğin adreslenen en küçük birimidir. Sözcük (word) 8086'da 16 bitlik, çift sözcük (double word) 32 bitlik öbektir. Bir öbeğin en soldaki biti en anlamlı bit (most significant bit, MSB), en sağdaki biti en az anlamlı bit (least significant bit, LSB) adını alır.

Sözcük genişliği işlemciye bağlıdır. 8086 16 bitlik bir işlemcidir: genel amaçlı yazmaçları 16 bittir ve veri yolu bir saat turunda 16 bit taşır. AX yazmacı iki bayttan oluşur. Yüksek baytı AH, düşük baytı AL'dir. AX = 1234h ise AH = 12h ve AL = 34h olur. 32 bitlik bir değer 8086'da tek bir yazmaca sığmaz; çarpma ve bölme komutları böyle değerleri DX:AX çiftinde tutar. Bu çiftte DX yüksek sözcüğü, AX düşük sözcüğü taşır.

1.2.2.5İkili sayıları okumak

Assembly kaynak kodunda ikili sayılar b harfiyle biter: 101b beştir. İkili bir sayının değerini bulmak için konumsal formül uygulanır. Rakamlar yalnız 0 ve 1 olduğu için çarpmaya gerek kalmaz. 0 olan basamaklar toplama hiçbir şey katmaz, 1 olan basamaklar ağırlıklarını katar. Kısa yol şudur: yalnız 1 olan basamakların ağırlıkları toplanır.

12⁷12802⁶012⁵3202⁴002³012²402¹012⁰1128 + 32 + 4 + 1 = 165
Şekil 1.2.7: 10100101b'nin değeri. 1 olan basamakların ağırlıkları 128, 32, 4 ve 1'dir; toplam 165.

8 bitlik ağırlıkları ezbere bilmek okumayı hızlandırır: soldan sağa 128, 64, 32, 16, 8, 4, 2, 1. Şekil 1.2.7 10100101b örneğini çözer: 128 + 32 + 4 + 1 = 165. Basamak sayısı 8'den az olan bir sayıda ağırlıklar yine sağdan başlar. Soldaki eksik basamaklar 0 kabul edilir.

Örnek 1.2.2

1111011b'yi onluğa çevirelim. Sayının yedi basamağı vardır; ağırlıklar sağdan 2⁰'dan 2⁶'ya kadar gider. Basamakları sağdan sola tek tek ekleyip ara toplamı izleyelim:

  1. Basamak 0: 1 × 2⁰ = 1, ara toplam 1.
  2. Basamak 1: 1 × 2¹ = 2, ara toplam 3.
  3. Basamak 2: 0 × 2² = 0, ara toplam 3.
  4. Basamak 3: 1 × 2³ = 8, ara toplam 11.
  5. Basamak 4: 1 × 2⁴ = 16, ara toplam 27.
  6. Basamak 5: 1 × 2⁵ = 32, ara toplam 59.
  7. Basamak 6: 1 × 2⁶ = 64, ara toplam 123.

Sonuç (1111011)2 = 1 + 2 + 0 + 8 + 16 + 32 + 64 = 123'tür. Kısa yolla bakılırsa yedi bitin hepsi 1 olsaydı değer 127 olurdu; 2² basamağı 0 olduğu için 127 − 4 = 123 bulunur.

12⁶6412⁵3212⁴1612³802²012¹212⁰1toplam = 123
Şekil 1.2.8: 1111011b'nin basamak ağırlıkları ve son ara toplam: 64 + 32 + 16 + 8 + 0 + 2 + 1 = 123.

Örneğin son cümlesindeki hile genel bir kuraldır. n bitin hepsi 1 olan sayı 2n − 1'dir. Birkaç biti 0 olan bir sayının değeri, bu üst sınırdan 0 olan bitlerin ağırlıkları çıkarılarak bulunabilir. Çoğu biti 1 olan sayılarda bu yol daha hızlıdır.

1.2.2.6Onaltılık sistem

İkili sayılar uzundur ve okunması yorucudur. 16 bitlik bir adresi 0 ve 1 dizisi olarak yazmak hem yer kaplar hem hata yapmayı kolaylaştırır. Onluk sistem kısa yazım sağlar, ama onluk ile ikili arasındaki dönüşüm bölme ve çarpma ister. Onaltılık sistem iki üstünlüğü birleştirir: kısadır ve ikiliye dönüşümü hesap gerektirmez.

Tanım 1.2.5

Onaltılık (hexadecimal) sistem, tabanı 16 olan konumsal sistemdir. On altı rakamı vardır: 0–9 ve 10–15 değerleri için A, B, C, D, E, F harfleri. Basamak ağırlıkları 16'nın kuvvetleridir: 1, 16, 256, 4096, 65 536, …

16 = 24 olduğu için her onaltılık rakam tam olarak dört bite, yani bir nibble'a karşılık gelir. Tablo 1.2.3 on altı nibble'ın onluk ve onaltılık karşılıklarını verir. Bu tablo, sayı sistemleriyle çalışırken ezbere bilinmesi gereken tek tablodur. Bir bayt iki onaltılık rakamla, bir sözcük dört onaltılık rakamla yazılır: 1010 0101b = A5h.

Tablo 1.2.3: On altı nibble ve onaltılık rakamlar.
OnlukİkiliOnaltılıkOnlukİkiliOnaltılık
000000810008
100011910019
200102101010A
300113111011B
401004121100C
501015131101D
601106141110E
701117151111F

Assembly'de onaltılık sayılar h harfiyle biter: 5Fh = 5 × 16 + 15 = 95. Harfle başlayan onaltılık sayıların önüne bir 0 eklenir: 0E120h. Bu sıfır sayının değerini değiştirmez, ama assembler'a bunun bir sayı olduğunu söyler. Sıfır konmazsa assembler E120h'yi bir değişkenin ya da etiketin adı sanır. Tablo 1.2.4 bu kuralın sonuçlarını özetler.

Tablo 1.2.4: Onaltılık sabitlerin yazımı.
YazımAnlamı
MOV AL, 0FFhAL = 255; doğru yazım
MOV AL, FFhhata: FFh tanımsız bir ad olarak okunur
MOV AX, 10onluk 10 (= 0Ah); sonek yoksa sayı onluktur

Onaltılık bir sayının onluk değeri yine konumsal formülle bulunur. 1234h için ağırlıklar 4096, 256, 16 ve 1'dir: 1 × 4096 + 2 × 256 + 3 × 16 + 4 × 1 = 4096 + 512 + 48 + 4 = 4660. Şekil 1.2.9 bu hesabı gösterir. Harfli rakamlar önce onluk değerlerine çevrilir, sonra çarpılır.

116³4096216²512316¹48416⁰44096 + 512 + 48 + 4 = 4660
Şekil 1.2.9: 1234h = 1·16³ + 2·16² + 3·16¹ + 4·16⁰ = 4096 + 512 + 48 + 4 = 4660.
Örnek 1.2.3

A12Fh'yi onluğa çevirelim. Önce harfler çözülür: A = 10, F = 15. Ağırlıklar 16⁰ = 1, 16¹ = 16, 16² = 256 ve 16³ = 4096'dır. Sağdan başlayarak:

  1. F × 16⁰ = 15 × 1 = 15; ara toplam 15.
  2. 2 × 16¹ = 32; ara toplam 47.
  3. 1 × 16² = 256; ara toplam 303.
  4. A × 16³ = 10 × 4096 = 40 960; ara toplam 41 263.

Sonuç (A12F)16 = 41 263'tür. Değer 65 535'ten küçük olduğu için 16 bitlik bir yazmaca sığar: MOV AX, 0A12Fh geçerli bir komuttur.

A16³40960116²256216¹32F16⁰15toplam = 41263
Şekil 1.2.10: A12Fh'nin basamak katkıları: 40 960 + 256 + 32 + 15 = 41 263.

1.2.2.7İkili ile onaltılık arasında dörtlü gruplama

Her onaltılık rakam dört bite karşılık geldiği için ikili ile onaltılık arasındaki dönüşüm, bir sözlükten kelime bakmak kadar kolaydır. İkili sayı sağdan başlayarak dörtlü öbeklere ayrılır. En soldaki öbek dört bitten kısaysa soluna 0 eklenir. Her öbek, Tablo 1.2.3 kullanılarak tek bir onaltılık rakama çevrilir.

Örnek 1.2.4

1010 1011 0101 1100b'yi onaltılığa çevirelim. Sayı zaten dörtlü öbeklere ayrılmıştır. 1010 = 8 + 2 = 10, yani A'dır. 1011 = 8 + 2 + 1 = 11, yani B'dir. 0101 = 4 + 1 = 5'tir. 1100 = 8 + 4 = 12, yani C'dir. Sonuç AB5Ch'dir. A ile başladığı için assembly'de 0AB5Ch diye yazılır.

Ters yön de aynı tabloyla yapılır: her onaltılık rakam dört bite açılır. 3Eh → 0011 1110b. Öbek sayısı tek olan bir örnek: 1101011b yedi bittir. Sağdan ayrılınca öbekler 110 ve 1011 olur. Soldaki öbeğe bir 0 eklenir: 0110 1011 → 6Bh.

1010101101011100AB5C
Şekil 1.2.11: 16 bitlik ikili sayının dörtlü öbekleri ve onaltılık rakamları: 1010 → A, 1011 → B, 0101 → 5, 1100 → C.

Programcıların ikili veriyi neredeyse her zaman onaltılık yazmasının nedeni budur. Bir bayt tam iki onaltılık rakamdır, bir sözcük tam dört. 8086 hata ayıklayıcıları ve emülatörleri yazmaç ve bellek içeriğini onaltılık gösterir. Bir yazmacın değeri onaltılık okunduğunda hangi bitlerin 1 olduğu bir bakışta görülür. Örneğin AL = 80h ise yalnız bit 7 birdir; AL = 0Fh ise düşük nibble'ın dört biti birdir.

Aynı yöntem sekizli (octal) sistem için de geçerlidir. 8 = 23 olduğu için her sekizli rakam üç bite karşılık gelir ve ikili sayı üçlü öbeklere ayrılır. 0100 0001b üçlü öbeklerle 001 000 001 diye yazılır; bu da 101o eder. Sekizli sistem eski bilgisayarlarda yaygındı; 8086 programlamada nadiren kullanılır.

Sık yapılan hata

Dörtlü öbekleri soldan başlayarak ayırmak. 1101011b soldan ayrılırsa 1101 ve 011 öbekleri çıkar; sağdaki öbeğe sağdan 0 eklenirse 1101 0110 = D6h bulunur. Bu yanlıştır: sağa eklenen sıfır sayıyı iki katına çıkarır. Öbekler her zaman sağdan, yani birler basamağından başlar; eksik bitler yalnız sola eklenir.

1.2.2.8Assembly'de sayı gösterimleri

emu8086 assembler'ı sabitleri dört tabanda ve karakter olarak kabul eder. Tabanı sayının sonundaki ek, yani sonek (suffix) belirler. Tablo 1.2.5 AL'ye 65 yükleyen beş farklı yazımı ve bir negatif sabiti listeler.

Tablo 1.2.5: Aynı değerin farklı yazımları.
YazımTabanAL'ye giden değer
MOV AL, 65onluk (sonek yok ya da d)65 = 41h
MOV AL, 41honaltılık65 = 41h
MOV AL, 01000001bikili65 = 41h
MOV AL, 101osekizli (o ya da q)65 = 41h
MOV AL, 'A'ASCII karakter65 = 41h
MOV AL, -1onluk, işaretliFFh

İlk beş satırın hepsi aynı makine kodunu üretir: B0 41. Burada B0h, “AL'ye sabit bir bayt yükle” komutunun işlem kodudur; 41h ise sabitin kendisidir. Assembler kaynak koddaki sayıyı hangi tabanda bulursa bulsun ikiliye çevirir ve komutun içine gömer. İşlemci kaynak kodu hiç görmez; yalnız 1011 0000 0100 0001 bitlerini görür. Taban, yalnız insanlar için bir yazım kolaylığıdır.

6541h01000001b101o'A'AL = 0100 0001b (B0 41)
Şekil 1.2.12: Beş farklı yazım aynı bayta dönüşür: 0100 0001b = 41h. Komutun makine kodu her durumda B0 41'dir.

Son satır ayrıca ilgi çekicidir: MOV AL, -1 AL'ye FFh yükler. Assembler negatif sabiti ikiye tümleyen gösterimine çevirir: −1 için 256 − 1 = 255 = FFh. AL'ye giden FFh bit deseni, MOV AL, 255'in yüklediği desenle aynıdır. İşlemci için ikisi arasında hiçbir fark yoktur.

Sık yapılan hata

Soneki unutmak. MOV AL, 41 AL'ye 41h değil, onluk 41'i, yani 29h'yi yükler. Bellek dökümünden ya da bir tablodan onaltılık bir değer kopyalanırken h eki yazılmazsa program hata vermeden yanlış değerle çalışır. Assembler bunu fark edemez, çünkü 41 geçerli bir onluk sayıdır.

1.2.3Taban dönüşümleri

Bir sayıyı başka bir tabandan onluğa çevirmek konumsal formülle yapılır: basamaklar ağırlıklarıyla çarpılıp toplanır. Ters yön, yani onluktan başka bir tabana geçiş, ayrı bir yöntem ister. Bu kesim tamsayı kısmı için bölme-kalan yöntemini, kesirli kısım için çarpma yöntemini anlatır. Her iki yöntemin neden çalıştığını gösterir ve aynı işi yapan iki küçük 8086 programını adım adım izler.

1.2.3.1Bölme-kalan yöntemi

Tanım 1.2.6

Bölme-kalan yöntemi, onluk bir tamsayıyı b tabanına çevirir. Sayı b'ye bölünür; bölüm saklanır, kalan bir basamak olarak yazılır. Bölüm 0 olana kadar bölme bölüm üzerinde sürdürülür. Kalanlar sondan başa (aşağıdan yukarı) okununca sayının b tabanındaki gösterimi elde edilir: ilk kalan en düşük basamaktır.

Yöntemin neden çalıştığı konumsal formülden görülür. N = dkbk + … + d1b + d0 yazalım. d0 dışındaki bütün terimler b'nin katıdır. Bu yüzden N, b'ye bölündüğünde kalan tam olarak d0'dır ve bölüm dkbk−1 + … + d1 olur. Bölüm, sayının en sağdaki basamağı silinmiş hâlidir. Onu yeniden b'ye bölmek d1'i verir. Her bölme bir basamak üretir ve sayıyı bir basamak kısaltır. Kalan her zaman 0 ile b − 1 arasında olduğu için her kalan geçerli bir rakamdır.

Onluk sistemde aynı yöntem kendiliğinden bilinir. 754'ü 10'a bölünce bölüm 75, kalan 4'tür; kalan son basamaktır. 75'i 10'a bölünce kalan 5, bölüm 7 olur. Yöntem, bu tanıdık işlemin başka bir tabanla yapılmasından ibarettir.

Örnek 1.2.5

39'u onaltılığa çevirelim. 39 ÷ 16 = 2, kalan 7'dir; 7 birler basamağıdır. 2 ÷ 16 = 0, kalan 2'dir. Bölüm 0 olduğu için durulur. Kalanlar aşağıdan yukarı okunur: 27h. Sağlama: 2 × 16 + 7 = 39.

39 ÷ 16= 2kalan72 ÷ 16= 0kalan2aşağıdan yukarı oku27h
Şekil 1.2.13: 39'un 16'ya art arda bölünmesi. Kalanlar 7 ve 2'dir; aşağıdan yukarı okununca 27h.
Örnek 1.2.6

Daha büyük bir sayı: 43 868'i onaltılığa çevirelim.

  1. 43 868 ÷ 16 = 2741, kalan 12 → C.
  2. 2741 ÷ 16 = 171, kalan 5.
  3. 171 ÷ 16 = 10, kalan 11 → B.
  4. 10 ÷ 16 = 0, kalan 10 → A. Bölüm 0: dur.

Kalanlar aşağıdan yukarı okununca AB5Ch bulunur. A ile başladığı için assembly'de 0AB5Ch yazılır. Sağlama: 10 × 4096 + 11 × 256 + 5 × 16 + 12 = 40 960 + 2816 + 80 + 12 = 43 868. Bu sayı, dörtlü gruplama örneğindeki 1010 1011 0101 1100b ile aynıdır.

43868 ÷ 16= 2741kalan12=C2741 ÷ 16= 171kalan5171 ÷ 16= 10kalan11=B10 ÷ 16= 0kalan10=Aaşağıdan yukarı oku0AB5Ch
Şekil 1.2.14: 43 868'in bölme merdiveni. Kalanlar C, 5, B, A sırasıyla çıkar; aşağıdan yukarı okununca 0AB5Ch.

Her bölme adımında kalanı hesaplamak için bölüm ile bölenin çarpımı sayıdan çıkarılır: 43 868 − 2741 × 16 = 43 868 − 43 856 = 12. Hesap makinesiyle çalışırken ondalık sonuç da kullanılabilir. 43 868 / 16 = 2741,75 çıkar. Tam kısım bölümdür, kesirli kısım 16 ile çarpılınca kalanı verir: 0,75 × 16 = 12.

1.2.3.2Kod izleme: DIV ile onaltılık basamaklar

Bölme-kalan yöntemi bir döngüdür ve doğrudan 8086 koduna dönüşür. 8086'nın DIV komutu bölümü ve kalanı tek komutta verir. Aşağıdaki program 2989'u 16'ya art arda böler ve kalanları kalan adlı bir diziye yazar.

ORG 100h
MOV AX, 2989   ; sayı
MOV BX, 16     ; taban
MOV SI, 0      ; sayaç
bol: MOV DX, 0 ; DX:AX
DIV BX         ; bölüm, kalan
MOV kalan[SI], DL
INC SI
CMP AX, 0      ; bölüm 0 mı?
JNE bol
RET
kalan DB 4 DUP(0)

Program satır satır şunu yapar. ORG 100h bir komut değil, assembler'a verilen bir yönergedir (directive). Programın .COM dosyası olarak kesimin 100h bağıl konumundan başlayacağını bildirir. MOV AX, 2989 bölünecek sayıyı AX'e koyar; 2989 onaltılık olarak 0BADh'dir. MOV BX, 16 böleni, yani hedef tabanı BX'e koyar. BX'e 2 ya da 8 yazılsaydı aynı kod ikili ya da sekizli basamakları üretirdi. MOV SI, 0 sıradaki kalanın dizideki yerini tutan indisi sıfırlar.

bol etiketli satır döngünün başıdır ve DX'i sıfırlar. Bunun nedeni DIV'in çalışma biçimidir. İşleneni 16 bitlik bir yazmaç olan DIV BX, 32 bitlik DX:AX çiftini BX'e böler. Bölümü AX'e, kalanı DX'e yazar. DX'te önceki turdan kalan bir değer bulunursa bölünen 65 536 × DX + AX olur ve sonuç tamamen yanlış çıkar. Bölüm 16 bite sığmazsa işlemci bir bölme hatası kesmesi de üretir. Bu yüzden her bölmeden önce DX = 0 yapılır.

MOV kalan[SI], DL kalanın düşük baytını dizinin SI. elemanına yazar. Kalan 16'dan küçük olduğu için DL'ye sığar ve DH her zaman 0'dır. INC SI indisi bir artırır. CMP AX, 0 AX'ten 0'ı çıkarır, sonucu bir yere yazmaz ama bayrakları kurar: bölüm 0 ise ZF = 1, değilse ZF = 0 olur. JNE bol (“eşit değilse atla”) ZF = 0 iken döngünün başına döner. Bölüm 0 olunca atlama yapılmaz ve RET programı bitirir. Son satır, dört baytlık ve başlangıçta sıfır olan kalan dizisini tanımlar.

Tablo 1.2.6 programın her önemli adımdan sonraki durumunu verir. Yazmaç değerleri onaltılık yazılmıştır.

Tablo 1.2.6: DIV programının izlemesi (2989 = 0BADh, taban 16).
AdımAXDXSIkalan (+0 … +3)Açıklama
ilk üç MOV0BADh0000h000 00 00 00BX = 0010h
tur 1: DIV BX00BAh000Dh000 00 00 002989 ÷ 16 = 186, kalan 13 (D)
MOV, INC, CMP00BAh000Dh10D 00 00 00AX ≠ 0 → ZF = 0, JNE atlar
tur 2: DIV BX000Bh000Ah10D 00 00 00186 ÷ 16 = 11, kalan 10 (A)
MOV, INC, CMP000Bh000Ah20D 0A 00 00AX ≠ 0 → JNE atlar
tur 3: DIV BX0000h000Bh20D 0A 00 0011 ÷ 16 = 0, kalan 11 (B)
MOV, INC, CMP0000h000Bh30D 0A 0B 00AX = 0 → ZF = 1, JNE atlamaz
RET0000h000Bh30D 0A 0B 00üç basamak bulundu

Döngü üç kez döner, çünkü 2989 onaltılık olarak üç basamaklıdır. SI'nin son değeri basamak sayısını verir. Bellekte kalanlar en düşük basamaktan başlayarak 0D 0A 0B sırasıyla durur. Sondan başa okununca B, A, D, yani 0BADh elde edilir. Sağlama: 11 × 256 + 10 × 16 + 13 = 2816 + 160 + 13 = 2989. Şekil 1.2.15 son durumu gösterir.

DIV BX ile bölme (taban 16)2989 ÷ 16 = 186kalan 13D186 ÷ 16 = 11kalan 10A11 ÷ 16 = 0kalan 11Bsondan başa okuAX0000hDX000BhSI0003hBX = 0010h (16)kalan dizisi0D0A0B00+0 +1 +2 +3
Şekil 1.2.15: Döngü bittikten sonra yazmaçlar ve kalan dizisi. Üç bölmenin kalanları D, A ve B; sondan başa okununca 0BADh.

Programda dizinin boyutu dört bayttır. 16 bitlik bir sayı onaltılık olarak en çok dört basamaklıdır (FFFFh), bu yüzden dört bayt her durumda yeter. Taban 2 yapılsaydı 16 basamak gerekirdi ve dizinin 16 DUP(0) diye tanımlanması gerekirdi. Kalanları ekrana yazdırmak için her biri bir ASCII karaktere çevrilmelidir: 0–9 için 30h, A–F için 37h eklenir (0Dh + 37h = 44h = 'D').

Programın hızı hakkında bir not düşmek gerekir. 8086'da 16 bitlik DIV en yavaş komutlardandır; yazmaç işlenenle yaklaşık 144–162 saat turu sürer. Aynı süre içinde onlarca MOV ya da ADD çalışabilir. Bölen 2'nin bir kuvveti olduğunda bölmeye hiç gerek yoktur: kaydırma komutları aynı işi çok daha hızlı yapar. 2'ye bölme bunun en sık görülen örneğidir.

1.2.3.3İkili tabana bölme

Bölme-kalan yöntemi her tabanda çalışır. İkili taban için bölen 2'dir ve kalan her zaman 0 ya da 1'dir. Tek sayıların kalanı 1, çift sayıların kalanı 0'dır.

Örnek 1.2.7

45'i ikiliye çevirelim.

  1. 45 ÷ 2 = 22, kalan 1.
  2. 22 ÷ 2 = 11, kalan 0.
  3. 11 ÷ 2 = 5, kalan 1.
  4. 5 ÷ 2 = 2, kalan 1.
  5. 2 ÷ 2 = 1, kalan 0.
  6. 1 ÷ 2 = 0, kalan 1. Bölüm 0: dur.

Kalanlar aşağıdan yukarı okununca 101101b bulunur. Sağlama: 32 + 8 + 4 + 1 = 45. 8 bitlik bir yazmaçta bu sayı 0010 1101b = 2Dh olarak durur.

45 ÷ 2= 22kalan122 ÷ 2= 11kalan011 ÷ 2= 5kalan15 ÷ 2= 2kalan12 ÷ 2= 1kalan01 ÷ 2= 0kalan1aşağıdan yukarı oku101101b
Şekil 1.2.16: 45'in 2'ye art arda bölünmesi. Altı kalan aşağıdan yukarı okununca 101101b.

Büyük sayılarda 2'ye bölme uzun sürer: 43 868 gibi bir sayı on altı adım ister. Daha hızlı yol, sayıyı önce onaltılığa çevirmek ve sonra her rakamı dört bite açmaktır. 45 ÷ 16 = 2, kalan 13 (D) olduğu için 45 = 2Dh'dir. 2 = 0010 ve D = 1101 açılınca 0010 1101b elde edilir. Bu yol iki bölme ve bir tablo bakışıyla biter.

1.2.3.4Kod izleme: kalanlar CF'den gelir

Bir ikili sayıyı bir bit sağa kaydırmak, onu 2'ye bölmektir. Onluk bir sayıda son basamağı silmek 10'a bölmek olduğu gibi, ikili bir sayıda son biti atmak da 2'ye bölmektir. Dışarı düşen bit ise bölmenin kalanıdır. 8086'nın SHR (shift right, sağa mantıksal kaydırma) komutu bu düşen biti elde bayrağına (CF) yazar. Aşağıdaki program bu gözlemi kullanır: DIV olmadan 45'in ikili basamaklarını sırayla CF'ye düşürür ve BL'de toplar.

ORG 100h
MOV AL, 45     ; bölünen
MOV CX, 8      ; 8 bit
bit: SHR AL, 1 ; kalan → CF
RCR BL, 1      ; CF → BL
LOOP bit
RET

MOV AL, 45 bölüneni AL'ye koyar: AL = 0010 1101b = 2Dh. MOV CX, 8 döngü sayacını kurar; AL'nin sekiz bitinin her biri için bir tur dönülecektir. SHR AL, 1 AL'nin bütün bitlerini bir sağa kaydırır. En soldaki bite 0 girer, en sağdaki bit CF'ye düşer. Sonuçta AL'de bölüm, CF'de kalan bulunur.

RCR BL, 1 (rotate through carry right, elde üzerinden sağa döndürme) BL'yi CF ile birlikte 9 bitlik bir halka gibi döndürür. CF'deki bit BL'nin bit 7'sine girer, BL'nin bit 0'ı da CF'ye çıkar. Böylece SHR'nin ürettiği kalan BL'nin en soluna yerleşir. Her turda BL'deki eski kalanlar bir sağa kayar ve yenisi en sola girer. LOOP bit CX'i bir azaltır; CX sıfır değilse bit etiketine döner. Bu komut, “CX'i azalt, sıfır değilse atla” işini tek komutta yapar ve bayrakları değiştirmez.

Tablo 1.2.7: SHR/RCR programının izlemesi. Her satır o turun LOOP komutundan sonraki durumdur; “SHR kalanı” o turda CF'ye düşen bittir.
TurBölmeSHR kalanıALBL (ikili)BLCX
başta——2Dh0000 000000h8
145 ÷ 2 = 22116h1000 000080h7
222 ÷ 2 = 1100Bh0100 000040h6
311 ÷ 2 = 5105h1010 0000A0h5
45 ÷ 2 = 2102h1101 0000D0h4
52 ÷ 2 = 1001h0110 100068h3
61 ÷ 2 = 0100h1011 0100B4h2
70 ÷ 2 = 0000h0101 10105Ah1
80 ÷ 2 = 0000h0010 11012Dh0

Tablo 1.2.7 sekiz turu verir. Program BL'yi sıfırlamaz; tabloda BL'nin başlangıçta 0 olduğu varsayılmıştır. Sonuç bu varsayıma bağlı değildir: sekiz turda BL'nin eski bitlerinin hepsi CF'ye çıkar ve bir sonraki SHR'nin kalanıyla ezilir. Her turda RCR, BL'nin bit 0'ını CF'ye çıkarır. Bu bit sekizinci tura kadar hep 0'dır, bu yüzden LOOP anında CF her turda 0 görünür. CF = 1 yalnız SHR ile RCR arasındaki kısa anda görülür: 1, 3, 4 ve 6. turlarda. İlk kalan sekiz turda sekiz kez sağa kayarak BL'nin bit 0'ına ulaşır. Son kalan ise BL'nin bit 7'sine yerleşir. Program bitince BL = 0010 1101b = 2Dh = 45'tir.

00010110AL= 22CF=100000000BL= 00hCX = 8bölme45 ÷ 2 = 22k 100000000AL= 0CF=000101101BL= 2DhCX = 0bölme45 ÷ 2 = 22k 122 ÷ 2 = 11k 011 ÷ 2 = 5k 15 ÷ 2 = 2k 12 ÷ 2 = 1k 01 ÷ 2 = 0k 10 ÷ 2 = 0k 00 ÷ 2 = 0k 0
Şekil 1.2.17: Solda ilk SHR AL, 1: 45 ÷ 2 = 22 (AL = 16h), düşen bit CF = 1. Sağda döngü bitince: AL = 0, BL = 0010 1101b = 2Dh.

Sonuç ilk bakışta şaşırtıcı görünebilir: program 45'i alıp yine 45 üretmiştir. Aslında öğretici olan da budur. AL zaten ikili bir sayı tutar; onu “ikiliye çevirmek” için bitleri yeniden yazmaya gerek yoktur. Program, 2'ye bölme kalanlarının sayının bitlerinin ta kendisi olduğunu gösterir. Kalanlar sondan başa dizilince sayının ikili gösterimi ortaya çıkar. Aynı fikir, bir sayının bitlerini tek tek işlemek için kullanılır: SHR ile düşürülen bit CF'den okunur ve JC ya da JNC ile karar verilir.

Sık yapılan hata

RCR yerine ROR kullanmak. ROR BL, 1 BL'yi CF'den bağımsız döndürür: bit 0 bit 7'ye geçer ve CF'ye yalnız kopyalanır. SHR'nin CF'ye düşürdüğü kalan BL'ye hiç girmez; program BL'nin başlangıç değerini döndürmekle kalır. Kalanın taşınması için dönmenin elde üzerinden (RCR) ya da SHR'den sonra CF'yi okuyan ayrı bir komutla yapılması gerekir.

1.2.3.5Kesirli kısım: 2 ile çarpma

Konumsal formül virgülün sağına da uzanır. Virgülden sonraki basamakların ağırlıkları tabanın negatif kuvvetleridir. Onlukta 0,375 = 3 × 10−1 + 7 × 10−2 + 5 × 10−3'tür. İkilide ise virgülden sonraki ağırlıklar 2−1 = 0,5, 2−2 = 0,25, 2−3 = 0,125, 2−4 = 0,0625 diye gider. 0,101b = 0,5 + 0,125 = 0,625'tir.

Tanım 1.2.7

Çarpma yöntemi, 0 ile 1 arasındaki onluk bir kesri ikiliye çevirir. Kesir 2 ile çarpılır; çarpımın tam kısmı (0 ya da 1) sıradaki kesir biti olur. Çarpımın kesirli kısmıyla devam edilir. Kesir 0 olunca ya da istenen bit sayısına ulaşınca durulur. Bitler yukarıdan aşağı, yani üretildikleri sırayla okunur: ilk bit 2−1 basamağıdır.

Yöntemin gerekçesi bölme yönteminin aynasıdır. x = 0,f1f2f3… (ikili) yazalım. 2x, virgülü bir sağa kaydırır: f1,f2f3…. Çarpımın tam kısmı f1'dir, kesirli kısmı ise kalan bitlerden oluşan sayıdır. Her çarpma bir biti virgülün soluna taşır. Bölmede ilk kalan en düşük basamaktı; çarpmada ilk tam kısım en yüksek kesir basamağıdır. Okuma yönünün tersine dönmesi bundan kaynaklanır.

Örnek 1.2.8

0,625'i ikiliye çevirelim.

  1. 0,625 × 2 = 1,25: tam kısım 1 (2−1 biti); kesir 0,25 ile devam.
  2. 0,25 × 2 = 0,5: tam kısım 0 (2−2 biti); kesir 0,5.
  3. 0,5 × 2 = 1,0: tam kısım 1 (2−3 biti); kesir 0, dur.

Bitler yukarıdan aşağı okununca 0,101b bulunur. Sağlama: 1/2 + 1/8 = 0,5 + 0,125 = 0,625.

Hem tam hem kesirli kısmı olan bir sayıda iki kısım ayrı ayrı çevrilir ve birleştirilir. 25,625 için 25 = 11001b (bölme yöntemiyle) ve 0,625 = 0,101b olduğundan 25,625 = 11001,101b olur.

0,625 × 2= 1,25bit1kalan kesir 0,250,25 × 2= 0,5bit0kalan kesir 0,50,5 × 2= 1,0bit1kalan kesir 0,0yukarıdan aşağı oku0,101b
Şekil 1.2.18: 0,625'in 2 ile art arda çarpılması. Tam kısımlar 1, 0, 1; yukarıdan aşağı okununca 0,101b.

Kesirli ikili sayılar onaltılığa da dörtlü gruplamayla çevrilir. Tek fark, öbeklerin virgülden başlayarak iki yana ayrılmasıdır. Tam kısım virgülden sola doğru, kesirli kısım virgülden sağa doğru öbeklenir. Kesirli kısımda eksik bitler sağa 0 olarak eklenir; virgülün sağına eklenen sıfır değeri değiştirmez. 1101,011b için öbekler 1101 ve 0110'dır, sonuç D,6h olur.

1.2.3.6Tekrar eden kesirler: 0,1

Her onluk kesir ikilide sonlu yazılamaz. 1/3 onlukta 0,333… diye sonsuza dek sürer; benzer biçimde 0,1 ikilide sonsuza dek sürer. Çarpma yöntemi bunu açıkça gösterir.

Örnek 1.2.9

0,1'i ikiliye çevirelim.

  1. 0,1 × 2 = 0,2 → bit 0; kesir 0,2.
  2. 0,2 × 2 = 0,4 → bit 0; kesir 0,4.
  3. 0,4 × 2 = 0,8 → bit 0; kesir 0,8.
  4. 0,8 × 2 = 1,6 → bit 1; kesir 0,6.
  5. 0,6 × 2 = 1,2 → bit 1; kesir 0,2.
  6. 0,2 × 2 = 0,4 → bit 0; ikinci adım tekrar ediyor.

Beşinci adımdan sonra kesir 0,2'ye döndü. 0,2 ikinci adımda görülmüştü; buradan sonra 2.–5. adımlar sonsuza dek tekrar eder ve 0011 bit deseni yinelenir. Sonuç 0,1 = 0,0 0011 0011 0011…b'dir. 8 kesir biti ile saklanırsa 0,0001 1001b = 0,097 656 25 elde edilir.

0,1 × 2= 0,2bit0kalan kesir 0,20,2 × 2= 0,4bit0kalan kesir 0,40,4 × 2= 0,8bit0kalan kesir 0,80,8 × 2= 1,6bit1kalan kesir 0,60,6 × 2= 1,2bit1kalan kesir 0,20,2 × 2= 0,4bit0kalan kesir 0,4tekrar eden00110,0 0011 0011 …b
Şekil 1.2.19: 0,1'in ikiliye çevrilmesi. Kesir 0,2'ye geri dönünce 0011 deseni sonsuza dek tekrar eder.

Hangi kesirlerin sonlu yazılabileceğini tek bir kural belirler. Bir kesir en sade hâlinde p/q ise ikilide sonlu yazılması için q'nun 2'nin bir kuvveti olması gerekir. 0,625 = 5/8'dir ve 8 = 2³ olduğu için üç bitle tam yazılır. 0,1 = 1/10'dur ve 10'un 5 çarpanı vardır; bu yüzden sonlu değildir. Onluk sistemde de aynı kural geçerlidir: paydası yalnız 2 ve 5 çarpanları içeren kesirler sonludur, 1/3 sonsuzdur.

Bu kuralın pratikteki sonucu önemlidir. Bilgisayar sınırlı sayıda bit kullandığı için 0,1 gibi değerleri ancak yaklaşık saklayabilir; fazla bitler kesilir ya da yuvarlanır. IEEE 754 kayan nokta biçiminde de 0,1 tam değil, yaklaşık olarak saklanır. Pek çok programlama dilinde 0,1 + 0,2 işleminin 0,3'e tam eşit çıkmamasının nedeni budur. Para gibi onluk kesirlerin tam tutulması gereken uygulamalarda BCD ya da kuruş cinsinden tamsayı kullanılır.

Sık yapılan hata

Kesir bitlerini bölme yöntemindeki gibi aşağıdan yukarı okumak. 0,625 için bitler 1, 0, 1 sırasıyla çıkar ve simetrik olduğu için yanlış okuma fark edilmez. 0,375 için ise bitler 0, 1, 1'dir: doğru sonuç 0,011b = 0,375'tir; ters okuma 0,110b = 0,75 verir. Bölmede kalanlar ters, çarpmada tam kısımlar düz okunur.

1.2.3.7Dönüşümleri birlikte kullanmak

Sunumdaki taban dönüştürücü, girilen bir sayıyı dört tabanda birden gösterir ve seçilen tabana bölme adımlarını listeler. Aynı işi elle yaparken izlenecek yol, kaynağa ve hedefe göre değişir. Tablo 1.2.8 en kısa yolları özetler.

Tablo 1.2.8: Tabanlar arası dönüşümde kısa yollar.
Kaynak → hedefYöntem
ikili/onaltılık/sekizli → onlukkonumsal formül: basamak × ağırlık toplamı
onluk → onaltılık16'ya bölme-kalan; kesir için 16 ile çarpma
onluk → ikiliönce onaltılığa, sonra her rakamı 4 bite açma; ya da 2'ye bölme
ikili ↔ onaltılıksağdan dörtlü öbekler; kesirde virgülden iki yana
ikili ↔ sekizlisağdan üçlü öbekler
onaltılık ↔ sekizliikili üzerinden: önce 4 bite aç, sonra 3'lü öbekle
Örnek 1.2.10

2024'ü onaltılık, ikili ve sekizli yazalım. 2024 ÷ 16 = 126, kalan 8; 126 ÷ 16 = 7, kalan 14 (E); 7 ÷ 16 = 0, kalan 7. Sonuç 7E8h'dir. Her rakam dört bite açılır: 0111 1110 1000b. Sekizli için aynı bitler sağdan üçlü öbeklenir: 011 111 101 000 → 3750o. Sağlama: 7 × 256 + 14 × 16 + 8 = 1792 + 224 + 8 = 2024 ve 3 × 512 + 7 × 64 + 5 × 8 + 0 = 2024.

1.2.4İşaretli sayılar

Buraya kadar bütün sayılar sıfır ya da pozitifti. Gerçek programlar ise sıcaklık farkları, borçlar, yön değişimleri gibi negatif değerlerle de çalışır. Kâğıt üzerinde negatif sayı önüne bir eksi işareti konarak yazılır. Bir yazmaçta ise eksi işareti için ayrı bir yer yoktur; yalnız bitler vardır. Bu kesim, negatif sayıların bitlerle nasıl gösterilebileceğini inceler ve 8086'nın kullandığı ikiye tümleyen gösterimini ayrıntılı ele alır.

1.2.4.1Desen ve yorum

0FFh pozitif mi negatiftir? Bit desenine bakarak bu soruya cevap verilemez. 1111 1111 deseni işaretsiz okunursa 255'tir, ikiye tümleyen gösterimiyle okunursa −1'dir. İşlemci bu iki yorumdan hangisinin kastedildiğini bilmez ve bilmesi de gerekmez. Yorumu, deseni kullanan komut ya da programcı belirler.

Tanım 1.2.8

İşaretsiz (unsigned) yorumda n bitlik desenler 0 ile 2n − 1 arasındaki değerleri gösterir. İşaretli (signed) yorumda desenlerin yarısı negatif sayılara ayrılır. 8086'nın kullandığı ikiye tümleyen (two's complement) gösteriminde −x negatif sayısı, 2n − x işaretsiz değerinin deseniyle yazılır.

8 bit ile 256 farklı desen vardır. İkiye tümleyende bunların ilk 128'i (00h … 7Fh, yani 0 … 127) sıfır ve pozitif sayıları gösterir. Sonraki 128'i (80h … FFh, yani işaretsiz 128 … 255) negatif sayıları gösterir. −5'i yazmak için 5, desen sayısından çıkarılır: 256 − 5 = 251 = FBh. −1 için 256 − 1 = 255 = FFh, −128 için 256 − 128 = 128 = 80h bulunur. Şekil 1.2.20 256 desenin iki yorumunu aynı eksen üzerinde gösterir.

00h … 7Fh80h … FFh (MSB = 1)işaretsiz: 0128255işaretli: 0+127−128−1FBh = 251 = 256 − 5 → −5
Şekil 1.2.20: 8 bitlik 256 desenin iki yorumu. 00h … 7Fh her iki yorumda 0 … 127'dir. 80h … FFh işaretsiz yorumda 128 … 255, işaretli yorumda −128 … −1'dir; bu desenlerin hepsinde MSB = 1'dir.

İki yorumun ortak bir özelliği vardır: negatif sayıların hepsinde en anlamlı bit 1'dir, pozitiflerin hepsinde 0'dır. Bu yüzden MSB'ye işaret biti (sign bit) denir. 8086 her aritmetik ve mantıksal işlemden sonra sonucun MSB'sini işaret bayrağına (SF) kopyalar. SF = 1 ise sonuç, işaretli yorumda negatiftir.

1.2.4.2Sayı çemberi

Sabit genişlikli bir yazmaç bir doğru gibi değil, bir çember gibi davranır. 4 bitlik bir yazmacı düşünelim. 0000'dan başlayıp 1 ekledikçe 0001, 0010, … 1111'e ulaşılır. 1111'e 1 eklenince sonuç 1 0000'dır; beşinci bit yazmaca sığmaz ve yazmaç 0000'a döner. Şekil 1.2.21 on altı deseni bir çemberin üzerine dizer. Saat yönünde bir adım ilerlemek 1 eklemek, ters yönde bir adım 1 çıkarmaktır.

000000110001220010330011440100550101660110770111−881000−791001−6101010−5111011−4121100−3131101−2141110−11511114 bitiç: işaretsizdaire: işaretli
Şekil 1.2.21: 4 bitlik sayı çemberi. Her desenin yanında içte işaretsiz değeri, dışta ikiye tümleyen değeri yazılıdır. 0000–0111 iki yorumda da 0–7'dir; 1000–1111 işaretsiz 8–15, işaretli −8 … −1'dir.

Çember iki “kopukluk” noktasını açıkça gösterir. Birincisi 1111 ile 0000 arasıdır. İşaretsiz yorumda burada 15'ten 0'a atlanır. Bir toplama bu noktayı geçerse sonuç işaretsiz yoruma sığmamıştır ve 8086 bunu elde bayrağıyla (CF) bildirir. İkincisi 0111 ile 1000 arasıdır. İşaretli yorumda burada +7'den −8'e atlanır. Bir işlem bu noktayı geçerse sonuç işaretli yoruma sığmamıştır ve 8086 bunu taşma bayrağıyla (OF) bildirir.

Çemberin en önemli dersi şudur: toplama ve çıkarma devresi iki yorum için de aynıdır. Çemberde bir adım ilerlemek, desenin hangi yorumla okunduğundan bağımsızdır. 1011 + 0001 = 1100 işlemi işaretsiz yorumda 11 + 1 = 12, işaretli yorumda −5 + 1 = −4'tür; iki sonuç da doğrudur. İşlemci tek bir toplayıcı kullanır ve iki yorum için ayrı bayraklar kurar. Hangi bayrağa bakılacağına program karar verir.

1.2.4.3Üç işaretli gösterim

Negatif sayıları göstermenin tek yolu ikiye tümleyen değildir. Tarihte üç gösterim kullanılmıştır. Tablo 1.2.9 4 bitlik on altı deseni dört yorumla karşılaştırır.

Tablo 1.2.9: 4 bitlik desenlerin dört yorumu.
İkiliİşaretsizİşaret-büyüklükBirler tümleyeniİkiye tümleyen
00000000
00011111
00102222
00113333
01004444
01015555
01106666
01117777
10008−0−7−8
10019−1−6−7
101010−2−5−6
101111−3−4−5
110012−4−3−4
110113−5−2−3
111014−6−1−2
111115−7−0−1
Tanım 1.2.9

İşaret-büyüklük (sign-magnitude) gösteriminde en üst bit işareti, kalan bitler sayının mutlak değerini gösterir. 4 bitte 0101 = +5, 1101 = −5'tir. Kâğıt üzerindeki eksi işaretinin doğrudan karşılığıdır.

İşaret-büyüklük gösterimi okuması en kolay olanıdır, ama iki ciddi sorunu vardır. Birincisi, sıfırın iki gösterimi vardır: 0000 = +0 ve 1000 = −0. Bir sayının sıfır olup olmadığını sınamak için iki deseni de denetlemek gerekir. İkincisi, toplama devresi karmaşıklaşır. +5 + (−3) işleminde 0101 ve 1011 doğrudan toplanırsa 1 0000 çıkar; bu, beklenen +2 değildir. Toplayıcının önce işaretleri karşılaştırması, sonra büyüklükleri toplaması ya da büyükten küçüğü çıkarması gerekir. Bu gösterim tamsayılarda bugün kullanılmaz. Kayan nokta sayılarının işaret biti ise aynı fikre dayanır.

1.2.4.4Birler tümleyeni

Tanım 1.2.10

Birler tümleyeni (one's complement) gösteriminde bir sayının negatifi, sayının bütün bitleri ters çevrilerek (0 → 1, 1 → 0) elde edilir. n bitte −x'in deseni (2n − 1) − x'tir. 8086'da NOT komutu bir işlenenin birler tümleyenini üretir.

8 bitlik bir örnek: +45 = 0010 1101b'dir. Bütün bitler ters çevrilince 1101 0010b = D2h elde edilir. Birler tümleyeni gösteriminde bu desen −45'tir. Aynı desen ikiye tümleyende −46'yı gösterir; iki gösterim birbirinden tam bir birim farklıdır. Şekil 1.2.22 işlemi bit bit gösterir.

+45 =001011012DhNOT →11010010D2h (−45, birler t.)
Şekil 1.2.22: +45 = 2Dh'nin bütün bitleri ters çevrilince D2h çıkar. Birler tümleyeni gösteriminde D2h = −45'tir.

Birler tümleyeni, işaret-büyüklüğün toplama sorununu büyük ölçüde çözer, ama iki kusur bırakır. Sıfırın yine iki gösterimi vardır: 0000 0000 = +0 ve 1111 1111 = −0. Ayrıca toplama sonucunda en üst bitten bir elde çıkarsa bu eldenin sonucun en düşük bitine geri eklenmesi gerekir; bu işleme çevrimsel elde (end-around carry) denir. 4 bitte −2 + 5: 1101 + 0101 = 1 0010 olur. Eldeki 1 geri eklenince 0010 + 1 = 0011 = 3 bulunur. Eski bazı bilgisayarlar (CDC 6600, UNIVAC 1100) bu gösterimi kullandı. Bugün birler tümleyeni tek başına bir sayı gösterimi olarak değil, ikiye tümleyenin ara adımı ve bit düzeyinde DEĞİL işlemi olarak karşımıza çıkar.

1.2.4.5İkiye tümleyen

İkiye tümleyen, birler tümleyeninin iki kusurunu tek bir hamleyle giderir: ters çevrilen desene 1 eklenir. Bu ekleme, −0 desenini ortadan kaldırır ve çevrimsel eldeye olan ihtiyacı yok eder.

Tanım 1.2.11

Bir sayının ikiye tümleyeni, önce bütün bitleri ters çevrilerek, sonra sonuca 1 eklenerek bulunur: −x = NOT x + 1. n bitte bu desen 2n − x'tir. 8086'da NEG komutu işlenenin ikiye tümleyenini tek adımda üretir; işlemi 0 − x çıkarması olarak yapar.

İki formülün aynı deseni verdiği kolayca gösterilir. n bitin hepsi 1 olan desen 2n − 1'dir. Bir sayının bitlerini ters çevirmek, onu bu desenden çıkarmakla aynıdır, çünkü 1 − 0 = 1 ve 1 − 1 = 0'dır ve hiçbir basamakta ödünç gerekmez. Dolayısıyla NOT x = (2n − 1) − x ve NOT x + 1 = 2n − x olur.

Örnek 1.2.11

−45'in 8 bitlik ikiye tümleyen gösterimini bulalım. +45 = 0010 1101b'dir. Bütün bitler ters çevrilince 1101 0010b çıkar. Buna 1 eklenince 1101 0011b = D3h bulunur. Sağlama: D3h = 211 = 256 − 45. İkinci sağlama toplamayla yapılır: D3h + 2Dh = 100h; 8 bitte sonuç 00h'dir, yani −45 + 45 = 0.

+45 =001011012DhNOT →11010010D2h+ 1 →11010011D3h = −45
Şekil 1.2.23: −45'in ikiye tümleyeni: 0010 1101 → NOT → 1101 0010 → +1 → 1101 0011 = D3h.

Elle hesapta daha hızlı bir kısa yol vardır. Sağdan başlayarak ilk 1'e kadar olan bitler (o 1 dahil) aynen yazılır, solda kalan bütün bitler ters çevrilir. 0010 1101 için en sağdaki bit zaten 1'dir; o aynen kalır, soldaki yedi bit ters çevrilir: 1101 0011. 0001 1000 (24) için sağdan ilk 1 bit 3'tedir: sağdaki 1000 aynen kalır, soldaki 0001 ters çevrilir: 1110 1000 = E8h = 256 − 24. Kısa yolun nedeni, 1 eklemenin sağdaki 1'ler dizisini sıfırlayıp ilk 0'ı 1 yapmasıdır.

İkiye tümleyenin iki önemli özelliği vardır. Birincisi, bir sayının ikiye tümleyeninin ikiye tümleyeni sayının kendisidir: 2n − (2n − x) = x. D3h'nin ikiye tümleyeni yeniden 2Dh'dir. Bu yüzden negatif bir sayının büyüklüğü, aynı işlemle bulunur. İkincisi, sıfırın tek bir gösterimi vardır. 0000 0000'ın ikiye tümleyeni 1111 1111 + 1 = 1 0000 0000'dır; dokuzuncu bit atılınca yine 0000 0000 kalır. Birler tümleyenindeki −0 deseni (1111 1111) ikiye tümleyende −1'dir.

İkiye tümleyende bir desenin işaretli değeri doğrudan da hesaplanabilir. MSB'nin ağırlığı negatif alınır, diğer bitler her zamanki gibi toplanır. 8 bitte ağırlıklar −128, 64, 32, 16, 8, 4, 2, 1'dir. D3h = 1101 0011b için −128 + 64 + 16 + 2 + 1 = −45 bulunur. Bu yorum, sabit noktalı kesirlerde de işe yarar.

1.2.4.6Kod izleme: NOT + 1 ile NEG

Aşağıdaki program aynı sayının ikiye tümleyenini iki yoldan hesaplar ve sonuçları karşılaştırır. Ardından −45 + 45 toplamını yapar ve aynı işlemi 16 bitte tekrarlar. Program, her komutun bayraklara etkisini görmek için iyi bir örnektir.

ORG 100h
MOV AL, 45       ; +45
MOV BL, AL
NOT BL           ; birler tümleyeni
INC BL           ; + 1
NEG AL           ; tek komutla
CMP AL, BL       ; aynı mı?
ADD AL, 45       ; -45 + 45
MOV AX, 45
NEG AX           ; 16 bitte -45
RET

MOV AL, 45 AL'ye 2Dh yükler; MOV BL, AL aynı değeri BL'ye kopyalar. MOV komutları bayrakları değiştirmez. NOT BL BL'nin bütün bitlerini ters çevirir: BL = D2h. NOT da hiçbir bayrağı etkilemez. INC BL BL'ye 1 ekler: BL = D3h. INC; ZF, SF, OF, AF ve PF bayraklarını kurar, ama CF'ye dokunmaz. Sonuç sıfır değildir (ZF = 0), MSB'si 1'dir (SF = 1).

NEG AL AL'yi 0 − AL olarak hesaplar ve aynı sonucu tek komutta verir: AL = D3h. NEG, işlenen sıfır değilse CF = 1 yapar; çünkü 0'dan sıfır olmayan bir sayı çıkarmak işaretsiz yorumda ödünç gerektirir. CMP AL, BL AL − BL farkını hesaplar ama sonucu yazmaz. D3h − D3h = 0 olduğu için ZF = 1, CF = 0, SF = 0 olur. ZF = 1, iki yolun aynı bit desenini ürettiğini gösterir.

ADD AL, 45 −45 ile +45'i toplar. D3h + 2Dh = 100h'dir. Dokuzuncu bit AL'ye sığmaz ve CF'ye düşer: CF = 1. AL = 00h olur; ZF = 1. İşaretli yorumda sonuç doğrudur (−45 + 45 = 0), bu yüzden OF = 0'dır. Bu satır, ikiye tümleyende CF = 1'in bir hata anlamına gelmediğini gösterir. MOV AX, 45 AX'e 002Dh yükler. NEG AX 16 bitlik ikiye tümleyeni hesaplar: 65 536 − 45 = 65 491 = FFD3h. Düşük bayt yine D3h'dir; üst bayt FFh olmuştur.

Tablo 1.2.10: NOT/NEG programının izlemesi. Bayraklar her komuttan sonraki değerdir; ilk satırda başlangıç değeri 0 alınmıştır.
KomutAXBLCFZFSFOFAçıklama
MOV AL, 45002Dh00h0000AL = +45
MOV BL, AL002Dh2Dh0000kopya
NOT BL002DhD2h0000birler tümleyeni; bayrak değişmez
INC BL002DhD3h0010D3h = −45; CF'ye dokunulmaz
NEG AL00D3hD3h10100 − 2Dh; işlenen ≠ 0 → CF = 1
CMP AL, BL00D3hD3h0100fark 0 → eşit
ADD AL, 450000hD3h1100D3h + 2Dh = 100h
MOV AX, 45002DhD3h1100MOV bayrağa dokunmaz
NEG AXFFD3hD3h101065 536 − 45 = FFD3h
11010011ALD3hişaretsiz 211 · işaretli −4511010011BLD3hişaretsiz 211 · işaretli −45CF1ZF0SF1OF0NEG = 0 − x1111111111010011AX= FFD3h · işaretsiz 65491 · işaretli −4511010011BLD3hişaretsiz 211 · işaretli −45CF1ZF0SF1OF016 bit NEG
Şekil 1.2.24: Solda NEG AL sonrası: AL = D3h, BL = D3h, CF = 1, SF = 1. Sağda NEG AX sonrası: AX = FFD3h (işaretsiz 65 491, işaretli −45).

Son iki satır, aynı sayının farklı genişliklerde nasıl yazıldığını gösterir. −45, 8 bitte D3h, 16 bitte FFD3h'dir. 16 bitlik gösterimin düşük baytı 8 bitlik gösterimin aynısıdır; üst bayt yalnız işaret bitinin kopyalarından (FFh) oluşur. Bu gözlem, işaret genişletmenin temelidir.

Sık yapılan hata

NOT ile NEG'i karıştırmak. NOT AL birler tümleyenini verir ve sonuç gerçek negatiften 1 eksiktir: AL = 2Dh iken NOT AL = D2h = −46. Bir sayının işaretini değiştirmek için NEG kullanılmalı ya da NOT'tan sonra INC eklenmelidir. Bir başka yanılgı, NEG sonrası CF = 1'i hata sanmaktır; NEG, işlenen sıfır olmadıkça her zaman CF = 1 verir.

1.2.4.7−5 + 5 = 0

Bir negatif sayı gösteriminin sağlaması gereken en temel kural, matematikteki −x + x = 0 eşitliğidir. İkiye tümleyende −5 = FBh = 1111 1011b'dir. Buna 5 = 0000 0101b eklenince toplam 1 0000 0000b = 256 olur. Dokuzuncu bit bayta sığmaz ve düşer; kalan 8 bitin hepsi sıfırdır. Şekil 1.2.25 toplamayı sütun sütun gösterir.

11111011−5 ya da 251+0000010151000000000bu bit düşer (bayta sığmaz) → CF = 18 bitlik sonuç = 0
Şekil 1.2.25: 1111 1011 (−5 ya da 251) + 0000 0101 (5) = 1 0000 0000. Dokuzuncu bit bayta sığmaz ve CF'ye düşer; 8 bitlik sonuç 0'dır.

Bu toplama, aynı toplayıcı devresinin iki yorum için de doğru sonuç verdiğinin bir örneğidir. İşaretsiz yorumda 251 + 5 = 256 sonucu 8 bite sığmamıştır; CF = 1 bunu bildirir. İşaretli yorumda −5 + 5 = 0 doğrudur ve OF = 0'dır. İkiye tümleyen bu yüzden seçilmiştir: negatif sayılar için ayrı bir devre gerekmez, toplayıcı desenlerin anlamını bilmeden çalışır. Bunun matematiksel nedeni, n bitlik toplamanın aslında 2n modülünde yapılmasıdır. Bu modülde 2n − x ile −x aynı sınıftadır.

1.2.4.8İşaretli aralıklar ve işaret genişletme

Tablo 1.2.11 8, 16 ve 32 bitlik sayıların işaretsiz ve işaretli aralıklarını verir. Her genişlikte desenlerin yarısı negatiftir.

Tablo 1.2.11: İşaretsiz ve işaretli (ikiye tümleyen) aralıklar.
GenişlikDesen sayısıİşaretsizİşaretliNegatif desenler
8 bit2560 … 255−128 … +12780h … FFh
16 bit65 5360 … 65 535−32 768 … +32 7678000h … FFFFh
32 bit4 294 967 2960 … 4 294 967 295−2 147 483 648 … +2 147 483 64780000000h … FFFFFFFFh

Aralık simetrik değildir: negatif taraf pozitiften bir fazladır. Bunun nedeni sıfırın pozitif tarafta yer almasıdır. 8 bitte 128 negatif ve 128 sıfır-ya-da-pozitif desen vardır; pozitifler 1 … 127, negatifler −1 … −128'dir. Bu asimetrinin ilginç bir sonucu vardır: −128'in pozitif karşılığı 8 bite sığmaz. NEG ile 80h'nin ikiye tümleyeni alınırsa 0111 1111 + 1 = 1000 0000 = 80h çıkar; sonuç değişmez ve 8086 OF = 1 ile taşmayı bildirir.

Tanım 1.2.12

İşaret genişletme (sign extension), işaretli bir değeri daha geniş bir yazmaca değeri değiştirmeden taşır: yeni eklenen üst bitlerin hepsine eski işaret biti kopyalanır. Sıfırla genişletme ise üst bitleri 0 yapar ve işaretsiz değerler için doğrudur. 8086'da CBW AL'yi AX'e, CWD AX'i DX:AX'e işaretle genişletir.

Genişletmenin neden işaret bitiyle yapıldığı ikiye tümleyen formülünden görülür. −5, 8 bitte 256 − 5 = FBh, 16 bitte 65 536 − 5 = FFFBh'dir. İki desen arasındaki fark yalnız üst baytın FFh olmasıdır. Pozitif bir sayıda ise üst bayt 00h olur: +5, 05h ve 0005h'dir. Her iki durumda da üst bitler işaret bitinin kopyasıdır. FBh sıfırla genişletilseydi 00FBh = +251 elde edilirdi; −5 değeri kaybolurdu.

Örnek 1.2.12

AL = 9Ch (−100) iken CBW çalışıyor. AL'nin MSB'si 1'dir; bu yüzden AH = FFh olur ve AX = FF9Ch elde edilir. Sağlama: 65 536 − 100 = 65 436 = FF9Ch. AL = 64h (+100) olsaydı MSB 0 olduğundan AH = 00h ve AX = 0064h olurdu. CWD aynı işi bir üst genişlikte yapar: AX = FF9Ch ise DX = FFFFh olur.

1.2.4.9Sabit noktalı işaretli kesirler

Kesirli sayılar için kayan nokta donanımı her zaman bulunmaz. 8086'nın kayan nokta komutu yoktur; birçok küçük mikrodenetleyicide de yoktur. Böyle sistemlerde kesirler tamsayı yazmaçlarında sabit noktalı olarak tutulur. Virgülün yeri önceden kararlaştırılır ve hiçbir yerde saklanmaz.

Tanım 1.2.13

Sabit noktalı sayı (fixed-point number), kesir noktasının yeri önceden belirlenmiş ikili sayıdır. Qm.f biçiminde sayı, işaret biti dahil m tamsayı biti ve f kesir bitinden oluşur. Deseni bir tamsayı olarak okuyup 2f'ye bölmek, sayının değerini verir.

8 bitlik Q5.3 biçimini düşünelim: son üç bit kesirdir. Basamak ağırlıkları soldan sağa −16, 8, 4, 2, 1, ½, ¼, ⅛'dir. En soldaki bitin ağırlığı ikiye tümleyende olduğu gibi negatiftir. Gösterilebilen değerler −16 ile +15,875 arasındadır ve ardışık iki değer arasındaki fark 1/8 = 0,125'tir.

Örnek 1.2.13

−6,75'i Q5.3 biçiminde yazalım. Önce +6,75 yazılır: 6,75 = 4 + 2 + ½ + ¼, yani 00110,110b = 36h. Negatif için ikiye tümleyen alınır; virgül yok sayılır. 0011 0110 ters çevrilince 1100 1001 olur; 1 eklenince 1100 1010 = CAh bulunur. Virgül yerine konunca 11001,010b okunur.

Sağlama ağırlıklarla yapılır: −16 + 8 + 1 + ¼ = −6,75. Daha kısa bir yol da vardır: sayı 2³ = 8 ile çarpılır ve tamsayı gibi işlenir. −6,75 × 8 = −54 ve 256 − 54 = 202 = CAh olur.

−168421½¼⅛+6,7500110110,36h−6,7511001010,CAh−16 + 8 + 1 + ¼ = −6,75 ✓
Şekil 1.2.26: Q5.3 biçiminde +6,75 = 36h ve −6,75 = CAh. İşaret bitinin ağırlığı −16'dır: −16 + 8 + 1 + ¼ = −6,75.

Sabit noktalı sayıların asıl üstünlüğü, toplamanın sıradan tamsayı toplaması olmasıdır. İşlemci için CAh sıradan bir bayttır; virgülün yeri yalnız programcının kabulüdür. −6,75 + 2,5 işleminde 2,5 × 8 = 20 = 14h'dir. CAh + 14h = DEh olur. DEh = 11011,110b, ağırlıklarla −16 + 8 + 2 + 1 + ½ + ¼ = −4,25'tir; beklenen sonuç da budur. Toplama ve çıkarma için ek bir donanım gerekmez. Çarpmada ise sonucun kesir bit sayısı ikiye katlanır ve sonuç f bit sağa kaydırılarak yeniden ölçeklenir.

Sunumdaki bit gezgini, 8 bitlik bir desenin işaretsiz, işaretli, BCD ve Gray kodu yorumlarını birlikte gösterir. Bitlerden biri değiştirildiğinde dört yorumun nasıl değiştiğine bakmak, desen ile yorum arasındaki ayrımı pekiştirir. Aynı amaçla İkiye Tümleyen Laboratuvarı da kullanılabilir.

1.2.5İkili ve onaltılık aritmetik

Bir mikroişlemcinin aritmetik-mantık birimi (arithmetic logic unit, ALU) toplama, çıkarma ve bit düzeyinde işlemleri ikili sayılar üzerinde yapar. Programcı ise sonuçları çoğu zaman onaltılık okur. Bu kesim iki tabanda toplama ve çıkarmayı elle yapmayı, çıkarmanın neden toplamaya indirgendiğini ve CF ile OF bayraklarının bir işlemden sonra nasıl kurulduğunu anlatır.

1.2.5.1İkili toplama ve tam toplayıcı

İkili toplama, onluk toplamayla aynı biçimde yapılır: sayılar alt alta yazılır, en düşük basamaktan başlanır ve sütunlar sırayla toplanır. Fark, bir sütun toplamının 2'ye ulaşınca eldeye dönüşmesidir. Bir sütunda iki rakam için dört durum vardır: 0 + 0 = 0, 0 + 1 = 1, 1 + 0 = 1 ve 1 + 1 = 10b. Son durumda sütuna 0 yazılır ve bir sonraki sütuna 1 elde (carry) aktarılır. Önceki sütundan gelen elde de eklenince toplam 3 (11b) olabilir; bu durumda sütuna 1 yazılır ve yine 1 elde çıkar.

0 + 0= 0elde 0yaz 00 + 1= 1elde 0yaz 11 + 0= 1elde 0yaz 11 + 1= 10elde 1yaz 0
Şekil 1.2.27: İki bitin toplanmasındaki dört durum. Yalnız 1 + 1'de elde oluşur: sütuna 0 yazılır, 1 elde çıkar.
Tablo 1.2.12: Tam toplayıcının doğruluk tablosu. a ve b toplanan bitler, cg gelen elde, s toplam biti, cç çıkan eldedir.
abcgscç
00000
00110
01010
01101
10010
10101
11001
11111

Tablo 1.2.12 tek bir sütunun bütün durumlarını verir. Bu tablo, sayısal tasarımdan bilinen tam toplayıcı (full adder) devresinin doğruluk tablosudur. Toplam biti üç girişin XOR'udur: s = a ⊕ b ⊕ cg. Çıkan elde, girişlerden en az ikisi 1 olduğunda 1'dir: cç = ab + cg(a ⊕ b). Sekiz tam toplayıcı, her birinin çıkan eldesi bir sonrakinin gelen eldesine bağlanarak zincirlenirse 8 bitlik bir toplayıcı elde edilir. Bu yapıya dalgalı elde toplayıcısı (ripple-carry adder) denir. En son tam toplayıcının çıkan eldesi, 8086'da CF bayrağına yazılan bittir.

Dalgalı elde toplayıcısının bir zayıflığı vardır: en üst bitin sonucu, eldenin en alttan en üste kadar bütün kapılardan geçmesini bekler. 16 bitlik bir toplamada gecikme, tek bir tam toplayıcının gecikmesinin yaklaşık 16 katıdır. Hızlı işlemciler bu yüzden eldeyi önceden hesaplayan (carry-lookahead) devreler kullanır. Mantık aynıdır; yalnız eldeler paralel hesaplanır.

Örnek 1.2.14

110001101b (397) ile 100001011b (267) sayılarını toplayalım. Sütunlar sağdan sola numaralanır.

  1. Basamak 0: 1 + 1 = 2 → 0 yaz, 1 elde.
  2. Basamak 1: 0 + 1 + 1 (elde) = 2 → 0 yaz, 1 elde.
  3. Basamak 2: 1 + 0 + 1 (elde) = 2 → 0 yaz, 1 elde.
  4. Basamak 3: 1 + 1 + 1 (elde) = 3 → 1 yaz, 1 elde.
  5. Basamak 4: 0 + 0 + 1 (elde) = 1 → 1 yaz, elde yok.
  6. Basamak 5: 0 + 0 = 0 → 0 yaz.
  7. Basamak 6: 0 + 0 = 0 → 0 yaz.
  8. Basamak 7: 1 + 0 = 1 → 1 yaz.
  9. Basamak 8: 1 + 1 = 2 → 0 yaz, 1 elde.
  10. Basamak 9: yalnız elde 1 → 1 yaz.

Sonuç 1010011000b'dir. Sağlama: 512 + 128 + 16 + 8 = 664 = 397 + 267. Toplanan sayılar 9 bitti, sonuç 10 bit oldu. 9 bitlik bir toplayıcıda en üstteki 1 sığmaz ve elde olarak dışarı çıkar.

elde397+ 267110011010101111001100000010111011= 664
Şekil 1.2.28: 110001101b + 100001011b = 1010011000b (397 + 267 = 664). Üst satır her sütuna gelen eldeyi gösterir.

1.2.5.2İkili çıkarma: tümleyenle toplama

Çıkarma da ödünç alarak sütun sütun yapılabilir. İşlemciler ise genellikle ayrı bir çıkarıcı devre kullanmaz. Çıkarma, toplamaya çevrilir: A − B = A + (−B). −B, B'nin ikiye tümleyenidir; ikiye tümleyen de bitleri ters çevirip 1 eklemekle bulunur. Bit ters çevirme her bit için bir XOR kapısıyla, 1 ekleme ise en alt tam toplayıcının gelen eldesini 1 yaparak sağlanır. Böylece aynı toplayıcı hem toplar hem çıkarır.

Örnek 1.2.15

4 bitte 1011 − 0110 (11 − 6) işlemini yapalım. A = 1011, B = 0110'dır. B'nin bitleri ters çevrilir: 1001. Buna 1 eklenir: 1010; bu, 4 bitte −6'dır. A ile toplanır: 1011 + 1010 = 10101. Sonuç 5 bittir. 4 bite sığmayan soldaki 1 atılır ve 0101 = 5 kalır. Sağlama: 11 − 6 = 5.

A =101111B =01106NOT B =1001birler tümleyeni+1 →1010−B (ikiye t.)A + (−B) =101015 bit: soldaki elde atılırsonuç =01015 ✓
Şekil 1.2.29: 1011 − 0110 işleminin ikiye tümleyenle yapılması: NOT B = 1001, −B = 1010, A + (−B) = 1 0101; soldaki elde atılınca 0101 = 5.

Bu örnekte atılan elde 1'dir ve sonuç doğrudur. A < B olsaydı ne olurdu? 0110 − 1011 (6 − 11) için 1011'in ikiye tümleyeni 0101'dir. 0110 + 0101 = 1011 olur ve elde çıkmaz. 1011 işaretli yorumda −5'tir; doğru sonuç da −5'tir. Elde çıkmaması, işaretsiz yorumda çıkarmanın ödünç gerektirdiğini, yani A'nın B'den küçük olduğunu gösterir.

8086 bu ilişkiyi CF bayrağında tersine çevirerek saklar. SUB ve CMP komutlarından sonra CF, işaretsiz yorumda ödünç (borrow) alınıp alınmadığını gösterir. Tümleyenle toplamada elde 1 çıktıysa ödünç yoktur ve CF = 0 olur. Elde çıkmadıysa ödünç vardır ve CF = 1 olur. Bu kural sayesinde CMP AX, BX sonrası CF = 1, işaretsiz yorumda AX < BX anlamına gelir. JB (“küçükse atla”) tam olarak bu bayrağa bakar.

1.2.5.3Onaltılık toplama

Onaltılık sayılar da sütun sütun toplanır. Rakamların değerleri onluk düşünülür (A = 10, …, F = 15). Bir sütunun toplamı 16'dan küçükse doğrudan yazılır. 16 ya da daha büyükse toplamdan 16 çıkarılır, kalan sütuna yazılır ve sola 1 elde verilir. Kural onluk toplamadakiyle aynıdır; yalnız eşik 10 yerine 16'dır.

Örnek 1.2.16

9A7Ch + 5B96h toplamını bulalım.

  1. C + 6 = 12 + 6 = 18 ≥ 16 → 18 − 16 = 2 yaz, 1 elde.
  2. 7 + 9 + 1 = 17 ≥ 16 → 17 − 16 = 1 yaz, 1 elde.
  3. A + B + 1 = 10 + 11 + 1 = 22 ≥ 16 → 22 − 16 = 6 yaz, 1 elde.
  4. 9 + 5 + 1 = 15 < 16 → F yaz, elde yok.

Sonuç F612h'dir. Sağlama onlukta: 9A7Ch = 39 548, 5B96h = 23 446 ve 39 548 + 23 446 = 62 994 = F612h. 8086'da AX = 9A7Ch, BX = 5B96h iken ADD AX, BX aynı sonucu verir. En soldaki sütundan elde çıkmadığı için CF = 0 olur.

elde+C679AB95121116FKontrol: 39548 + 23446= 62994 ✓= F612h
Şekil 1.2.30: 9A7Ch + 5B96h = F612h. Üç sütundan elde çıkar, en soldaki sütundan çıkmaz.

Bu toplamın bir ayrıntısı daha vardır. İşaretli yorumda 9A7Ch negatiftir (MSB = 1), 5B96h pozitiftir. Farklı işaretli iki sayının toplamı hiçbir zaman işaretli taşma üretmez; bu yüzden OF = 0'dır. F612h işaretli yorumda −2542'dir: −25 988 + 23 446 = −2542.

1.2.5.4Onaltılık çıkarma

Onaltılık çıkarmada üstteki rakam alttakinden küçükse soldaki sütundan 1 ödünç alınır. Ödünç alınan 1, sağdaki sütunda 16 değerindedir. Ödünç veren sütunun rakamı 1 azalır.

Örnek 1.2.17

9A7Ch − 5B96h farkını bulalım.

  1. C − 6 = 12 − 6 = 6; ödünç yok.
  2. 7 − 9 olmaz: soldan ödünç alınır. 7 + 16 − 9 = 14 = E; soldaki A, 9'a iner.
  3. 9 − B olmaz: yine ödünç. 9 + 16 − 11 = 14 = E; soldaki 9, 8'e iner.
  4. 8 − 5 = 3; ödünç yok.

Sonuç 3EE6h'dir. Sağlama: 39 548 − 23 446 = 16 102 = 3EE6h. En soldaki sütunda ödünç gerekmediği için SUB AX, BX sonrası CF = 0 olur.

ödünç−C679AB956−1E−1E3Kontrol: 39548 − 23446= 16102 ✓= 3EE6h
Şekil 1.2.31: 9A7Ch − 5B96h = 3EE6h. “−1” işaretleri ödünç veren sütunları gösterir.

1.2.5.515'e ve 16'ya tümleyen

İkili tabandaki birler ve ikiye tümleyenin onaltılık karşılıkları 15'e ve 16'ya tümleyendir. Bunlar onaltılık çıkarmayı, tıpkı ikilide olduğu gibi, toplamaya çevirir.

Tanım 1.2.14

k basamaklı onaltılık bir sayının 15'e tümleyeni, her basamağın F'den çıkarılmasıyla bulunur ve 16k − 1 − x'e eşittir. 16'ya tümleyeni, 15'e tümleyene 1 eklenerek bulunur ve 16k − x'e eşittir. 4 basamaklı onaltılık sayı 16 bit olduğu için 16'ya tümleyen, 16 bitlik ikiye tümleyenle aynı desendir.

Örnek 1.2.18

5B96h'nin 15'e tümleyeni: F − 5 = A, F − B = 4, F − 9 = 6, F − 6 = 9 → A469h. 16'ya tümleyeni A469h + 1 = A46Ah'dir; bu 10000h − 5B96h'ye eşittir. Şimdi 9A7Ch − 5B96h, 9A7Ch + A46Ah olarak hesaplanır: toplam 13EE6h'dir. Dört basamağı aşan 1 atılır ve 3EE6h kalır. Doğrudan çıkarmayla aynı sonuç bulunmuştur.

Ters yönde 5B96h − 9A7Ch hesaplayalım. 9A7Ch'nin 16'ya tümleyeni 10000h − 9A7Ch = 6584h'dir. 5B96h + 6584h = C11Ah olur ve dört basamağı aşan elde çıkmaz. Elde çıkmaması sonucun negatif olduğunu gösterir. Büyüklüğü bulmak için C11Ah'nin 16'ya tümleyeni alınır: 10000h − C11Ah = 3EE6h. Sonuç −3EE6h, yani −16 102'dir.

15'e tümleyenFFFFh − 5B96h= A469hher basamak F'den çıkarılır16'ya tümleyenA469h + 1= A46Ah= 10000h − 5B96h9A7C − 5B969A7Ch + A46Ah= 1 3EE6htaşan 1 atılır → 3EE6h ✓5B96 − 9A7C5B96h + 6584h= C11Ahtaşan yok → sonuç negatif−(16'ya t. C11Ah)= −3EE6h10000h − C11Ah = 3EE6h
Şekil 1.2.32: 15'e ve 16'ya tümleyenle çıkarma. 9A7Ch − 5B96h = 9A7Ch + A46Ah = 1 3EE6h (elde atılır); 5B96h − 9A7Ch = 5B96h + 6584h = C11Ah (elde yok, sonuç −3EE6h).

8086'da AX = 5B96h ve BX = 9A7Ch iken SUB AX, BX doğrudan AX = C11Ah verir. Ödünç alındığı için CF = 1 olur. C11Ah işaretli yorumda −16 102'dir; programcı sonucu işaretli okuyorsa ek bir işlem gerekmez. İşaretsiz okuyorsa CF = 1, sonucun anlamsız olduğunu, çünkü küçük sayıdan büyüğün çıkarıldığını söyler.

1.2.5.6Elde ve işaretli taşma

Sabit genişlikteki bir yazmaçta her işlemin sonucu yazmaca sığmayabilir. Sığmama iki farklı biçimde olur ve 8086 bunları iki ayrı bayrakla bildirir. Bu iki bayrağı karıştırmak, assembly programlamadaki en yaygın hatalardan biridir.

Tanım 1.2.15

Elde bayrağı (CF), işaretsiz yorumda sonucun hedefe sığmadığını gösterir: toplamada en üst bitten elde çıkmıştır, çıkarmada ödünç alınmıştır. Taşma bayrağı (OF), işaretli yorumda sonucun hedefin aralığına sığmadığını gösterir (overflow). Donanım OF'yi şöyle kurar: işaret bitine giren elde ile işaret bitinden çıkan elde farklıysa OF = 1'dir.

İşaretli taşmanın belirtisi, sonucun işaretinin beklenenin tersi çıkmasıdır. İki pozitif sayının toplamı negatif çıkarsa ya da iki negatif sayının toplamı pozitif çıkarsa taşma olmuştur. Farklı işaretli iki sayının toplamı ise hiçbir zaman taşmaz: sonuç her zaman iki sayının arasında kalır ve aralığın içindedir. Çıkarmada durum terstir: A − B = A + (−B) olduğu için farklı işaretli sayıların farkı taşabilir, aynı işaretli sayıların farkı taşamaz. Tablo 1.2.13 altı durumu 8 bitlik örneklerle verir.

Tablo 1.2.13: 8 bitte işaretli taşma kuralı. CF sütunu aynı işlemin işaretsiz yorumunu gösterir.
İşlemİşaretlerÖrnekİşaretli yorumOFCF
A + B+ ile +50h + 40h = 90h80 + 64 → −112 (yanlış)10
A + B− ile −9Ch + CEh = 6Ah−100 + (−50) → +106 (yanlış)11
A + Bfarklı64h + CEh = 32h100 + (−50) = 5001
A − B+ eksi −64h − CEh = 96h100 − (−50) → −106 (yanlış)11
A − B− eksi +9Ch − 32h = 6Ah−100 − 50 → +106 (yanlış)10
A − Baynı9Ch − CEh = CEh−100 − (−50) = −5001

Tablonun CF sütunu iki bayrağın birbirinden bağımsız olduğunu gösterir. Birinci satırda CF = 0 ama OF = 1'dir: 80 + 64 = 144 işaretsiz yorumda 255'e sığar, işaretli yorumda 127'yi aşar. Üçüncü satırda CF = 1 ama OF = 0'dır: işaretsiz yorumda 100 + 206 = 306 bayta sığmaz, işaretli yorumda 100 − 50 = 50 doğrudur. Hangi bayrağın anlamlı olduğu, programcının sayıları nasıl yorumladığına bağlıdır. İşaretsiz sayılarla çalışan bir program CF'ye, işaretli sayılarla çalışan bir program OF'ye bakar.

Örnek 1.2.19

50h + 40h işleminde donanım kuralını uygulayalım. 0101 0000 + 0100 0000 toplanırken bit 6'da 1 + 1 = 10b olur: bit 6'dan bit 7'ye (işaret bitine) 1 elde girer. Bit 7'de 0 + 0 + 1 = 1 olur; işaret bitinden elde çıkmaz. Giren elde 1, çıkan elde 0'dır; ikisi farklı olduğu için OF = 1'dir. Çıkan elde 0 olduğu için CF = 0'dır. Sonuç 1001 0000 = 90h'dir.

9Ch + CEh işleminde ise 1001 1100 + 1100 1110 toplanır. Bit 6'da 0 + 1 + (bit 5'ten gelen 0) = 1 olur; işaret bitine elde girmez. Bit 7'de 1 + 1 = 10b olur; elde çıkar. Giren 0, çıkan 1 olduğu için OF = 1, çıkan elde 1 olduğu için CF = 1'dir. Sonuç 0110 1010 = 6Ah'dir.

Kuralın mantığı şöyle açıklanır. İşaret bitinden çıkan elde, işaretsiz taşmayı gösterir. İşaret bitine giren elde ise alt yedi bitin toplamının 127'yi aştığını gösterir. İki pozitif sayıda çıkan elde yoktur; giren elde varsa sonuç işaret bitini bozmuştur. İki negatif sayıda çıkan elde her zaman vardır; giren elde yoksa sonuç işaret bitini 0'a düşürmüştür. Giren ile çıkan eşitse işaret biti doğru kalmıştır.

Genişlikleri farklı işaretli sayılar toplanacaksa kısa olan önce işaretle genişletilmelidir. FBh (−5) ile 0100h (256) toplanacak olsun. FBh işaretle genişletilince FFFBh olur: FFFBh + 0100h = 1 00FBh ve 16 bitlik sonuç 00FBh = 251'dir. Doğru sonuç da −5 + 256 = 251'dir. FBh sıfırla genişletilseydi 00FBh + 0100h = 01FBh = 507 çıkardı; bu yanlıştır. 8086'da CBW bu işi tek komutla yapar.

Sık yapılan hata

CF = 1'i her durumda “sonuç yanlış” diye okumak. İşaretli sayılarla çalışırken CF anlamsızdır: −5 + 5 işleminde CF = 1'dir ama sonuç (0) doğrudur. Tersine, işaretsiz sayılarla çalışırken OF anlamsızdır: 80 + 64 işleminde OF = 1'dir ama işaretsiz sonuç (144) doğrudur. Bayrak, yalnız programcının seçtiği yoruma göre okunur.

Bayrak Laboratuvarı simülatörü, seçilen iki işlenen için toplama ve çıkarma sonrası CF, OF, SF, ZF ve diğer bayrakları gösterir. Tablodaki satırları orada denemek, iki bayrak arasındaki farkı somutlaştırır.

1.2.5.7Assembler'ın sabit ifadeleri

emu8086 assembler'ı sabit ifadelerde bir dizi işleç kabul eder. Bu işleçler programın yazılmasını kolaylaştırır: bir maske ya da bir adres farkı elle hesaplanmak yerine ifade olarak yazılabilir. Tablo 1.2.14 desteklenen işleçleri örnekleriyle listeler.

Tablo 1.2.14: emu8086'nın sabit ifadelerde desteklediği işleçler.
İşleçAnlamÖrnek → değerÇalışma zamanındaki karşılığı
~bütün bitleri tersler~0Fh → F0h (8 bit)NOT
*çarpma3*4 → 12MUL
/tamsayı bölme17/5 → 3DIV (bölüm)
%kalan17%5 → 2DIV (kalan)
+toplama40h+2 → 42hADD
-çıkarma, tekli eksi-5 → FBhSUB, NEG
<<sola kaydırma1<<4 → 16SHL
>>sağa kaydırma80h>>3 → 10hSHR
&bit düzeyinde VE0F0h&3Ch → 30hAND
^bit düzeyinde XOR0Fh^05h → 0AhXOR
|bit düzeyinde VEYA0F0h|0Fh → FFhOR

Bu ifadeler derleme zamanında hesaplanır. MOV AX, 3*4+1 yazıldığında assembler 13'ü hesaplar ve makine koduna MOV AX, 13 komutunu yazar. İşlemci çalışırken çarpma yapmaz. Bu yüzden ifadeler yalnız sabitlerle çalışır: MOV AX, BX*2 geçersizdir, çünkü BX'in değeri derleme zamanında bilinmez. Çalışma zamanında aynı işlemler tablonun son sütunundaki komutlarla yapılır. BX'i 2 ile çarpmak için örneğin SHL BX, 1 kullanılır.

1.2.6Bitin donanımdaki karşılığı

Buraya kadar bitler soyut 0 ve 1'ler olarak ele alındı. Bir mikroişlemcide ise her bit fiziksel bir büyüklüktür: bir hattaki gerilim ya da bir devrenin kararlı durumu. Bu kesim, gerilim düzeylerinin bitlere nasıl karşılık geldiğini ve bitlerin flip-flop'larda nasıl saklandığını anlatır. Konular sayısal tasarımdan bilinir; burada 8086'nın yazmaçları ve saat sinyaliyle ilişkileri öne çıkarılır.

1.2.6.1İkili sinyaller ve gerilim düzeyleri

Bir programın komutları ve verileri bellekte rakam öbekleri olarak durur. Bu rakamlar devrelerde gerilim ve akım olarak var olur. Sayısal bilgisayarlar iki tür sinyal kullanır: yüksek düzey 1'i, düşük düzey 0'ı temsil eder. 8086 gibi 5 V ile beslenen bir devrede yüksek düzey 5 V'a, düşük düzey 0 V'a yakındır.

Gerilimin tam 5 V ya da tam 0 V olması gerekmez. Her mantık ailesi bir giriş için eşik aralıkları tanımlar. TTL (transistor-transistor logic) ailesinde 2,0 V ve üzeri bir giriş 1, 0,8 V ve altı bir giriş 0 kabul edilir. Arada kalan bölge tanımsızdır ve kararlı çalışan bir devrede bir sinyal orada ancak geçiş sırasında bulunur. Çıkış tarafında ise daha sıkı sınırlar vardır: bir TTL çıkışı 1 için en az 2,4 V, 0 için en çok 0,4 V verir. Çıkış ile giriş eşikleri arasındaki 0,4 V'luk pay gürültü payıdır (noise margin). Hatta bu kadar gürültü eklense bile alıcı bit değerini doğru okur. Sayısal devrelerin gürültüye dayanıklı olmasının nedeni budur. Analog bir devrede sinyale eklenen her gürültü değeri bozar; sayısal devrede eşiği aşmayan gürültü hiçbir iz bırakmaz.

8086'nın adres ve veri yolları bu tür hatlardan oluşur. 20 adres hattı aynı anda 20 biti, 16 veri hattı aynı anda 16 biti taşır. Bir MOV komutu bellekten bir sözcük okuduğunda bellek yongası 16 veri hattının her birini yüksek ya da düşük düzeye çeker. İşlemci bu düzeyleri saatin belirli bir anında örnekler ve yazmacına alır.

1.2.6.2Flip-flop

Bir biti bir sonraki işleme kadar saklamak için belleği olan bir devre gerekir. Kapılardan oluşan bileşimsel bir devre girişleri değişince çıkışını da değiştirir; geçmişi hatırlamaz. Geri beslemeli devreler ise hatırlar.

Tanım 1.2.16

Flip-flop, bir biti saklayan ve durumunu saat sinyaline bağlı olarak değiştiren temel bellek devresidir. İki çıkışı vardır: saklanan bit Q ve onun tersi Q′. Girişindeki değer, saat sinyalinin belirli bir anında devreye yüklenir ve bir sonraki o ana kadar saklanır.

Şekil 1.2.33 saat girişli bir SR flip-flop'u gösterir. Devrenin kalbi, çapraz bağlanmış iki VEYA-DEĞİL (NOR) kapısıdır. Her kapının çıkışı ötekinin girişine geri beslenir. Bu geri besleme, iki kararlı durum yaratır: Q = 1, Q′ = 0 ya da Q = 0, Q′ = 1. Girişler 0 iken devre bulunduğu durumda kalır; biti “hatırlar”. S ve R girişleri saat sinyaliyle VE kapılarından geçer. Böylece girişler yalnız saat 1 iken etkili olur.

RSClkQQ′VEVEVEYA-DEĞİLVEYA-DEĞİL
Şekil 1.2.33: Saat girişli SR flip-flop. R ve S girişleri Clk ile VE kapılarından geçer; çapraz bağlı iki VEYA-DEĞİL kapısı Q ve Q′ çıkışlarını üretir.

1.2.6.3Flip-flop türleri

Uygulamada dört flip-flop türü kullanılır. Hepsi bir bit saklar; girişlerinin anlamı farklıdır. Tablo 1.2.15 dört türün davranışını özetler.

Tablo 1.2.15: Flip-flop türleri ve saat darbesindeki davranışları.
TürGirişlerDavranışÖzellik
SR (set-reset)S, RS = 1 → Q = 1; R = 1 → Q = 0; S = R = 0 → değişmezS = R = 1 yasaktır
D (veri)DQ ← Dyazmaç ve bellek hücresi
JKJ, KJ = 1 → Q = 1; K = 1 → Q = 0; J = K = 0 → değişmez; J = K = 1 → Q tersine döneryasak durumu yoktur
T (tersleme)TT = 1 → Q tersine döner; T = 0 → değişmezsayaç, frekans bölücü

SR flip-flop'ta S = R = 1 girişi yasaktır. Bu durumda iki NOR kapısının çıkışı da 0 olur ve Q ile Q′ birbirinin tersi olmaktan çıkar. Girişler aynı anda 0'a dönerse devrenin hangi duruma düşeceği kapı gecikmelerine bağlıdır ve öngörülemez. JK flip-flop bu durumu yararlı bir işe çevirir: J = K = 1 iken her saat darbesinde çıkış tersine döner. JK'yı esnek yapan bu üçüncü özelliktir. J ve K girişleri birleştirilip tek bir T girişi yapılınca T flip-flop elde edilir. T = 1 tutulan bir T flip-flop'un çıkışı her iki saat darbesinde bir tam periyot üretir, yani saat frekansını ikiye böler. Zincirlenen T flip-flop'lar ikili bir sayaç oluşturur.

Örnek 1.2.20

Bir JK flip-flop'ta başlangıçta Q = 0'dır ve J = K = 1 tutulurken üç yükselen saat kenarı gelir. Her kenarda çıkış tersine döner: 0 → 1 → 0 → 1. Üç kenardan sonra Q = 1'dir. Kenar sayısı çift olsaydı Q yine 0 olurdu.

1.2.6.4D flip-flop ve yazmaç

Mikroişlemcilerde en çok kullanılan tür D flip-flop'tur. Tek bir veri girişi vardır ve saatin yükselen kenarında D'deki değer Q'ya kopyalanır. Şekil 1.2.34 bir zamanlama diyagramı üzerinde bu davranışı gösterir.

ClkDQQ, yalnızca saatin yükselen kenarında (kesikli çizgiler) D'nin o anki değerini alır
Şekil 1.2.34: D flip-flop zamanlaması. Q yalnız saatin yükselen kenarında (kesikli çizgiler) D'nin o anki değerini alır; kenarlar arasında D'deki değişiklikler Q'yu etkilemez.

Diyagramda D girişi saat kenarları arasında birkaç kez değişir, ama Q bu değişikliklerden etkilenmez. Yalnız yükselen kenar anında D örneklenir ve değer bir sonraki kenara kadar Q'da saklanır. Bu, 1 bitlik bir bellektir. Yan yana konmuş 16 D flip-flop ortak bir saat ve bir yükleme sinyaliyle sürülürse 16 bitlik bir yazmaç elde edilir. 8086'nın AX, BX gibi yazmaçları ilke olarak böyle kurulmuştur. Bir MOV AX, BX komutu, BX'in çıkışlarının iç veri yolu üzerinden AX'in D girişlerine taşınması ve bir saat kenarında AX'e yüklenmesidir. Bayrak yazmacındaki her bayrak da bir flip-flop'tur.

Saat sinyali bütün bu yüklemelerin ne zaman olacağını belirler. 8086'nın bütün iç işlemleri saat turlarına bölünür. 5 MHz'lik bir saatte bir saat turu (clock cycle) 1 / 5 000 000 s = 200 ns sürer. Bir komutun kaç tur sürdüğü, kaç iç adımdan oluştuğuna bağlıdır. Yazmaçtan yazmaca bir MOV 2 tur, 16 bitlik bir DIV 144–162 tur sürer. Bir bellek okuması ise en az 4 turluk bir yol döngüsü (T1–T4) gerektirir.

1.2.7Kayan noktalı sayılar: IEEE 754

Sabit noktalı gösterim, virgülün yeri sabit olduğu için ya çok büyük ya çok küçük sayıları tutabilir; ikisini birlikte tutamaz. Q5.3 biçiminde en küçük adım 0,125'tir ve en büyük değer 16'nın altındadır. Bilimsel hesaplarda ise hem 6 × 1023 gibi büyük hem 1,6 × 10−19 gibi küçük sayılar gerekir. Bilimsel gösterimdeki fikir ikiliye taşınınca kayan nokta biçimi elde edilir: sayı bir kesir ile 2'nin bir kuvvetinin çarpımı olarak yazılır ve virgül, üsse göre “kayar”.

1.2.7.1Tek duyarlıklı biçim

Tanım 1.2.17

IEEE 754 tek duyarlıklı (single precision) kayan noktalı sayı 32 bittir ve üç alandan oluşur: 1 bitlik işaret s (bit 31), 8 bitlik üs e (bit 30–23) ve 23 bitlik kesir (fraction, mantissa) f (bit 22–0). Üs 127 kaydırmalı saklanır. Normalize bir sayının değeri

değer = (−1)s × 1,f × 2e − 127

ifadesidir. Buradaki 1, saklanmayan gizli bittir.

00111110001000000000000000000000işaretüs (8 bit)kesir / mantissa (23 bit)313023220
Şekil 1.2.35: IEEE 754 tek duyarlıklı biçimin alanları: bit 31 işaret, bit 30–23 üs, bit 22–0 kesir. Gösterilen desen 3E200000h'dir.

Biçimin üç ayrıntısı açıklama ister. Birincisi, işaret ayrı bir bittir: kayan noktalı sayılar ikiye tümleyen değil, işaret-büyüklük mantığıyla saklanır. Bir sayının negatifini almak için yalnız bit 31 ters çevrilir. İkincisi, üs kaydırmalı (biased) saklanır: gerçek üse 127 eklenir. Böylece −126 … +127 arasındaki üsler 1 … 254 arasındaki işaretsiz sayılarla yazılır. Kaydırmanın yararı, iki pozitif kayan noktalı sayının desenlerinin işaretsiz tamsayı gibi karşılaştırılabilmesidir. Üçüncüsü, normalize bir ikili sayı her zaman 1 ile başlar: 1,xxx × 2k. Baştaki 1 hep aynı olduğu için saklanmaz ve kesir alanına bir bit daha sığar. Bu yüzden 23 bitlik alan 24 bitlik duyarlık verir.

8086'nın kayan nokta komutu yoktur. Kayan nokta işlemleri ya 8087 matematik yardımcı işlemcisiyle ya da tamsayı komutlarıyla yazılmış yazılım yordamlarıyla yapılır. 8087, 8086'nın yanına takılan ve kendi yazmaç yığınıyla bu biçimdeki sayılar üzerinde çalışan ayrı bir yongadır. 64 bitlik çift duyarlıklı (double) biçim aynı fikri 1 + 11 + 52 bitle uygular; üs kaydırması 1023'tür.

1.2.7.2Çözümleme

Örnek 1.2.21

0 01111100 01000000000000000000000 deseninin, yani 3E200000h'nin değerini bulalım.

  1. İşaret biti 0'dır: sayı pozitiftir, çarpan (+1).
  2. Üs alanı 0111 1100b = 124'tür. Gerçek üs 124 − 127 = −3'tür: çarpan 2−3.
  3. Kesir alanı 0100…0'dır: 0 × 2−1 + 1 × 2−2 = 0,25. Gizli bitle birlikte 1,25 olur.
  4. Değer (+1) × 1,25 × 2−3 = 1,25 / 8 = 0,156 25'tir.

Desenin onaltılık yazımı alanlar bir araya getirilip dörtlü öbeklenerek bulunur: 0011 1110 0010 0000 … = 3E200000h.

1.2.7.3Kodlama

Örnek 1.2.22

−6,5'i 32 bitlik IEEE 754 biçimine çevirelim.

  1. Sayı negatiftir: işaret biti 1.
  2. Büyüklük ikiliye çevrilir: 6 = 110b, 0,5 = 0,1b; 6,5 = 110,1b.
  3. Normalize edilir: virgül iki basamak sola kayar, 110,1b = 1,101b × 2².
  4. Üs: 2 + 127 = 129 = 1000 0001b.
  5. Kesir: gizli 1 atılır, kalan 101 sağa 0'larla 23 bite tamamlanır: 1010 0000 0000 0000 0000 000.
  6. Alanlar birleştirilir: 1 10000001 10100000000000000000000 = 1100 0000 1101 0000 0000 … = C0D00000h.
11000000110100000000000000000000işaretüs (8 bit)kesir / mantissa (23 bit)313023220
Şekil 1.2.36: −6,5'in IEEE 754 deseni: işaret 1, üs 1000 0001 (129), kesir 101 ve sıfırlar; C0D00000h.

8086 belleğinde bu desen düşük adresten başlayarak 00 00 D0 C0 sırasıyla durur; en düşük bayt en düşük adrese yazılır (little-endian düzen).

1.2.7.4Özel desenler

Üs alanının iki uç değeri (0 ve 255) özel anlamlara ayrılmıştır. Tablo 1.2.16 bunları listeler.

Tablo 1.2.16: IEEE 754'ün özel desenleri.
DesenAnlam
e = 0, f = 0±0 (işaret bitine göre +0 ya da −0)
e = 255, f = 0±∞ (ör. 1/0)
e = 255, f ≠ 0NaN, “sayı değil” (ör. 0/0)
e = 0, f ≠ 0normalize edilmemiş, çok küçük sayı: 0,f × 2−126

Sıfır, gizli bit kuralıyla yazılamaz; 1,f her zaman en az 1'dir. Bu yüzden sıfır için ayrı bir desen tanımlanmıştır. İşaret bitinin ayrı olması +0 ile −0'ı doğurur; standart ikisinin karşılaştırmada eşit sayılmasını ister. Sonsuz ve NaN değerleri, bir hesabın hata verip durmak yerine sürmesini sağlar. Normalize edilmemiş sayılar ise sıfıra yakın bölgedeki boşluğu doldurur. En küçük normalize sayı 2−126'dır; bunun altındaki değerler gizli bit olmadan 0,f × 2−126 olarak saklanır.

Kayan noktalı sayıların duyarlığı sınırlıdır. Tek duyarlıkta 24 bitlik anlamlı kısım, yaklaşık 7 onluk basamağa karşılık gelir. 0,1 gibi ikilide sonlu olmayan bir değer bu 24 bite yuvarlanarak saklanır: tek duyarlıkta 3DCCCCCDh deseni 0,100 000 001 49… değerini gösterir. Bu küçük hata, toplamalar art arda yapıldığında birikir.

1.2.8İkili kodlu onluk (BCD)

İkili sistem hesap için verimlidir, ama insanlar onluk okur. Bir sayıyı ekrana basmak için onu her seferinde 10'a bölüp basamaklarına ayırmak gerekir; bu da yavaş bir DIV dizisi ister. Sayıların sık sık gösterildiği ve az hesaplandığı uygulamalarda başka bir kodlama kullanılır: her onluk basamak ayrı ayrı ikili yazılır.

Tanım 1.2.18

İkili kodlu onluk (binary-coded decimal, BCD) kodlamada her onluk basamak dört bitle gösterilir: 0 = 0000, …, 9 = 1001. 1010 … 1111 desenleri geçersizdir. Paketli BCD bir bayta iki basamak koyar (25 → 25h); paketsiz BCD her bayta bir basamak koyar (25 → 02h 05h).

BCD ile ikili arasındaki fark bir örnekle görülür. 25 BCD olarak 0010 0101'dir: soldaki nibble 2'yi, sağdaki 5'i gösterir. Aynı sayının ikili karşılığı ise 0001 1001 = 19h'dir. Paketli BCD'de bir baytın onaltılık yazımı, onluk değerin rakamlarının aynısıdır: BCD 25 = 25h. Bu özellik, BCD sayıların bellek dökümünde okunmasını çok kolaylaştırır. Bedeli, alanın verimsiz kullanılmasıdır: bir bayt ikili olarak 0 … 255'i, paketli BCD olarak yalnız 0 … 99'u tutar.

BCD 250010010125ikili 2500011001= 19h (16 + 8 + 1)
Şekil 1.2.37: 25'in BCD ve ikili gösterimi. BCD'de her nibble bir onluk basamaktır (0010 0101); ikilide sayı bütün olarak yazılır (0001 1001 = 19h).

BCD, onluk basamakların doğrudan gösterildiği yerlerde kullanılır. Bilgisayarlardaki gerçek zamanlı saat (RTC) yongası saati, dakikayı ve tarihi BCD olarak tutar; 14:35, 14h ve 35h baytlarıyla saklanır. 7 bölütlü göstergeler bir BCD basamağı alıp ilgili bölütleri yakan kod çözücülerle sürülür. Hesap makineleri ve finansal yazılımlar, 0,1 gibi onluk kesirlerin tam saklanması için BCD aritmetiği kullanır.

1.2.8.1BCD toplama ve düzeltme

İki paketli BCD sayı ikili toplayıcıyla toplanırsa sonuç her zaman geçerli BCD olmaz. Bir nibble'ın toplamı 9'u aşınca ikili toplayıcı onu 10 … 15 arasında bırakır; oysa onluk sistemde 10'a ulaşan basamak eldeye dönüşmelidir. Bu fark bir düzeltme ile giderilir: geçersiz basamağa 6 eklenir. 6 sayısı, bir nibble'ın 16 deseni ile onluk basamağın 10 değeri arasındaki farktır. 6 eklemek, kullanılmayan altı deseni (1010 … 1111) atlar ve eldeyi bir üst nibble'a geçirir.

Örnek 1.2.23

BCD 38 ile BCD 45'i toplayalım. 38 = 0011 1000, 45 = 0100 0101'dir. İkili toplam 0111 1101 = 7Dh'dir. Düşük nibble 1101 = 13'tür ve BCD'de geçersizdir. Bu nibble'a 6 eklenir: 7Dh + 06h = 83h = 1000 0011. Sonuç BCD 83'tür ve 38 + 45 = 83 doğrudur.

380011 100038h+ 450100 010145h= ?0111 11017Dh1101 = 13 > 9 → geçersiz basamak+ 60000 0110düzeltme= 831000 001183h1000 0011BCD 83 ✓
Şekil 1.2.38: BCD 38 + 45. İkili toplam 7Dh'nin düşük basamağı (13) geçersizdir; 6 eklenince 83h, yani BCD 83 elde edilir.

Düzeltme gereken ikinci bir durum vardır: düşük nibble geçerli görünür ama aslında taşmıştır. 29 + 18 işleminde ikili toplam 29h + 18h = 41h'dir. Düşük nibble 1'dir ve geçerli görünür; oysa 9 + 8 = 17'dir. Düşük nibble'dan bir üst nibble'a elde çıkmış ve 16 değerinde götürmüştür. 8086 bu eldeyi yardımcı elde bayrağında (AF) tutar. AF = 1 ise düşük nibble'a yine 6 eklenir: 41h + 6 = 47h, yani BCD 47 = 29 + 18. Yüksek basamak 9'u aşarsa ya da ondan elde çıkarsa ona da 6 eklenir, yani bayta 60h eklenir; bu durumda CF = 1 olur ve sonuç 100'ü aşmıştır.

8086 bu kuralların hepsini tek bir komutla uygular: DAA (decimal adjust after addition). ADD AL, BL ile iki paketli BCD sayı toplandıktan hemen sonra DAA çalıştırılırsa AL geçerli BCD'ye düzeltilir. DAA, AL'nin düşük nibble'ına ve AF'ye, sonra yüksek nibble'ına ve CF'ye bakarak 06h, 60h ya da 66h ekler. Çıkarma için eşi DAS'tır. DAA yalnız AL üzerinde çalışır; çok basamaklı BCD sayılar bayt bayt, eldeyle (ADC) toplanıp her bayttan sonra DAA uygulanarak işlenir.

Sık yapılan hata

Yalnız “nibble 9'dan büyük mü?” sorusuna bakıp AF'yi unutmak. 29h + 18h = 41h'de düşük nibble 1'dir ve düzeltme gerekmiyor gibi görünür; ama sonuç 41 değil 47 olmalıdır. Bir başka hata, BCD sayıyı onaltılık sayı gibi okumaktır: 47h onaltılık olarak 71'dir, ama BCD olarak 47'dir. 2Fh ise onluk 47'nin ikili karşılığıdır ve BCD değildir.

1.2.9Bayt sıralaması: little-endian ve big-endian

Bellek bayt bayt adreslenir. 16 ya da 32 bitlik bir değer belleğe yazılırken baytlarının hangi sırayla dizileceği bir tasarım kararıdır. İki karşıt gelenek vardır.

Tanım 1.2.19

Little-endian düzende çok baytlı bir değerin en az anlamlı baytı en düşük adrese yazılır. Big-endian düzende en anlamlı bayt en düşük adrese yazılır. 8086 ve bütün x86 ailesi little-endian'dır.

32 bitlik değer 12345678h, adres 0100h'den itibaren:Little-endian (Intel x86)78h0100h56h0101h34h0102h12h0103hLSB (78h) en düşük adresteBig-endian (ağ, PowerPC)12h0100h34h0101h56h0102h78h0103hMSB (12h) en düşük adreste
Şekil 1.2.39: 12345678h değerinin 0100h adresinden başlayarak iki düzende yerleşimi. Little-endian: 78 56 34 12; big-endian: 12 34 56 78.

Şekil 1.2.39 32 bitlik 12345678h'yi iki düzende gösterir. Little-endian'da 0100h adresinde 78h, 0103h adresinde 12h durur. Bellek dökümü soldan sağa okununca değer “ters” görünür. Big-endian'da ise baytlar yazıldığı sırayla durur ve döküm doğrudan okunur. Big-endian kullanan sistemler arasında Motorola 68000, çoğu PowerPC yapılandırması ve ağ protokolleri vardır. İnternet protokolleri çok baytlı alanları big-endian iletir; bu düzene “ağ bayt sırası” (network byte order) denir. Bir x86 makinesi ağdan gelen 16 bitlik bir port numarasını kullanmadan önce baytlarını yer değiştirmelidir.

Little-endian düzenin bir kolaylığı vardır: bir değerin adresi, değerin genişliğinden bağımsız olarak düşük baytı gösterir. 0100h adresindeki bir sözcüğün düşük baytını okumak için yine 0100h adresine bakılır. 8086'da MOV AX, [0100h] komutu AL'yi 0100h'den, AH'yi 0101h'den yükler. Aynı adresten MOV AL, [0100h] yalnız düşük baytı alır ve aynı değerin düşük baytını bulur.

Örnek 1.2.24

DD 0A1B2C3D4h ile DS:0300h adresine 32 bitlik A1B2C3D4h yazılmış olsun. Little-endian düzende baytlar 0300h: D4h, 0301h: C3h, 0302h: B2h, 0303h: A1h olur. Şimdi şu üç komutu düşünelim. MOV AX, [0302h] AL'yi 0302h'den (B2h), AH'yi 0303h'den (A1h) alır: AX = A1B2h. MOV BL, [0301h] tek bayt okur: BL = C3h. MOV CX, [0301h] CL'yi 0301h'den (C3h), CH'yi 0302h'den (B2h) alır: CX = B2C3h. Son okuma tek adresten başlayan bir sözcük okumasıdır; 8086 bunu iki ayrı yol döngüsüyle yapar ve fazladan dört saat turu harcar.

Sık yapılan hata

Little-endian'ı bitlerin ters dizilmesi sanmak. Sıralama bayt düzeyindedir; her baytın kendi içindeki bitler değişmez. 1234h belleğe 34 12 diye yazılır, 43 21 ya da 2C 48 diye değil. Bir başka hata, DW 1234h ile tanımlanmış bir sözcüğü MOV AL, [adres] ile okuyunca 12h beklemektir; düşük adreste 34h vardır.

1.2.10Gray kodu

Sıradan ikili sayımda ardışık iki sayı arasında birden çok bit değişebilir. 3'ten 4'e geçerken 011 → 100 olur ve üç bit birden değişir. Bir döner kodlayıcının ya da bir sayacın çıkışında bu bitler fiziksel olarak tam aynı anda değişmez. Geçiş anında okunan değer, örneğin 111 (7) ya da 000 (0) gibi, ne 3 ne 4 olan bir ara değer olabilir. Gray kodu bu sorunu kökten çözer.

Tanım 1.2.20

Gray kodu (Gray code), ardışık her iki değeri arasında yalnız bir bitin değiştiği kodlamadır. İkili bir B sayısının Gray kodu G = B XOR (B >> 1) formülüyle bulunur.

Tablo 1.2.17: 3 bitlik ikili ve Gray kodları. “Değişen bit”, Gray kodunda bir önceki satıra göre değişen bitin sağdan sırasıdır.
OnlukİkiliGrayDeğişen bit
0000000—
10010011
20100112
30110101
41001103
51011111
61101012
71111001

Tablo 1.2.17 3 bitlik diziyi verir: 000, 001, 011, 010, 110, 111, 101, 100. 3'ten 4'e geçiş Gray kodunda 010 → 110'dur; yalnız en üst bit değişir ve hatalı bir ara değer okunamaz. Dizi kendi içinde de kapanır: 7'den (100) 0'a (000) geçişte de tek bit değişir. Bu yüzden Gray kodu, bir milin açısını ölçen döner kodlayıcılarda (rotary encoder) çok kullanılır. Analog-sayısal dönüştürücülerin bazı türlerinde ve Karnaugh haritalarının satır-sütun sıralamasında da aynı kod karşımıza çıkar. Tek bit değişimi, geçişlerin elektriksel gürültüye ve zamanlama farklarına karşı dayanıklı olmasını sağlar.

1.2.10.1İkiliden Gray koduna ve geri

Formülün anlamı şudur: Gray kodunun en yüksek biti ikiliyle aynıdır; her sonraki bit, ikilideki kendisi ile solundaki bitin XOR'udur. B >> 1, her bitin solundaki biti kendi konumuna getirir; XOR da iki biti karşılaştırır. Gray kodunda bir bit 1 ise ikilide o bit ile solundaki bit farklıdır.

Örnek 1.2.25

B = 0110 (6) için Gray kodunu bulalım. B bir bit sağa kaydırılır: B >> 1 = 0011. Bit bit XOR alınır: 0110 ⊕ 0011 = 0101. 6'nın Gray kodu 0101'dir. Kuralla sağlama: en yüksek bit 0; sonra 0 ⊕ 1 = 1, 1 ⊕ 1 = 0, 1 ⊕ 0 = 1 → 0101.

B0110ikili (6)B >> 10011bir sağa kaydırB XOR (B >> 1)0101Gray
Şekil 1.2.40: 6 = 0110'nın Gray kodu: B >> 1 = 0011 ve 0110 ⊕ 0011 = 0101.

Gray kodundan ikiliye dönüş ters yönde ilerler. İkilinin en yüksek biti Gray'in en yüksek bitine eşittir. Sonraki her bit, ikilide bir önce bulunan bit ile Gray'deki aynı konumdaki bitin XOR'udur: Bi = Bi+1 ⊕ Gi. 0101 için: B3 = 0; B2 = 0 ⊕ 1 = 1; B1 = 1 ⊕ 0 = 1; B0 = 1 ⊕ 1 = 0. Sonuç 0110 = 6'dır. Dönüş, ileri yön gibi tek adımda değil, bitten bite ilerleyen bir zincirle yapılır.

1.2.10.2Kod izleme: SHR ve XOR ile Gray kodu

Formül 8086'da üç komutla yazılır: değeri kopyala, kopyayı bir sağa kaydır, iki değeri XOR'la. Aşağıdaki program ardışık iki sayının, 11 ve 12'nin Gray kodunu hesaplar.

ORG 100h
MOV AL, 1011b  ; 11
MOV BL, AL
SHR BL, 1      ; B >> 1
XOR BL, AL     ; G
MOV AL, 1100b  ; 12
MOV BH, AL
SHR BH, 1
XOR BH, AL     ; G
RET

MOV AL, 1011b AL'ye 11 yükler. MOV BL, AL değeri BL'ye kopyalar; kaydırma kopya üzerinde yapılacak, B değeri AL'de korunacaktır. SHR BL, 1 BL'yi bir sağa kaydırır: 0000 1011 → 0000 0101. En sağdaki 1 CF'ye düşer, en sola 0 girer. XOR BL, AL iki değeri bit bit karşılaştırır: 0101 ⊕ 1011 = 1110. BL = 0Eh, 11'in Gray kodudur. XOR komutu CF ve OF'yi her zaman 0 yapar; ZF ve SF'yi sonuca göre kurar. Programın ikinci yarısı aynı işi 12 için BH üzerinde yapar: 1100 → SHR → 0110 → XOR → 1010 = 0Ah.

Tablo 1.2.18: Gray kodu programının izlemesi.
KomutALBLBHAçıklama
MOV AL, 1011b0Bh00h00hB = 11
MOV BL, AL0Bh0Bh00hkopya
SHR BL, 10Bh05h00h0101b; düşen bit CF = 1
XOR BL, AL0Bh0Eh00h1011 ⊕ 0101 = 1110: Gray(11)
MOV AL, 1100b0Ch0Eh00hB = 12
MOV BH, AL0Ch0Eh0Chkopya
SHR BH, 10Ch0Eh06h0110b; düşen bit CF = 0
XOR BH, AL0Ch0Eh0Ah1100 ⊕ 0110 = 1010: Gray(12)
B (AL)1100= 12B >> 1 (BH)0110= 6G (BH)1010= 10xorGray(11) = 1110Gray(12) = 1010yalnız bit 2 farklı
Şekil 1.2.41: Programın sonunda: Gray(11) = 1110 (BL), Gray(12) = 1010 (BH). İki kod yalnız bit 2'de farklıdır.

Sonuç, Gray kodunun temel özelliğini doğrular. 11'den 12'ye geçişte ikilide üç bit değişir: 1011 → 1100. Gray kodunda ise yalnız bir bit değişir: 1110 → 1010. Programda BL ve BH aynı BX yazmacının iki yarısıdır; program bitince BX = 0A0Eh olur. BH ve BL yazmaçları ayrı ayrı adreslenebildiği için iki 8 bitlik sonuç tek bir 16 bitlik yazmaçta yan yana durur.

1.2.11Özet

  • Konumsal sistemde bir sayının değeri, her rakamın taban üzeri konum ağırlığıyla çarpımlarının toplamıdır: N = Σ di × bi. Romen rakamlarında sıfır ve basamak olmadığı için aritmetik zordur.
  • Bilgisayarlar iki durumlu elemanlarla kolay kurulduğu için ikili sistemi kullanır. n bit 2n desen verir: bayt 0 … 255, sözcük 0 … 65 535.
  • Onaltılık bir rakam tam bir nibble'dır; ikili ile onaltılık arasında sağdan dörtlü öbeklerle geçilir. Assembly'de b, h, o sonekleri tabanı belirtir; harfle başlayan onaltılık sayının önüne 0 konur. Taban yalnız yazım biçimidir: 65, 41h ve 'A' aynı B0 41 kodunu üretir.
  • Onluktan başka tabana tamsayı kısmı bölme-kalan yöntemiyle çevrilir ve kalanlar aşağıdan yukarı okunur. Kesirli kısım 2 ile çarpma yöntemiyle çevrilir ve bitler yukarıdan aşağı okunur. Paydası 2'nin kuvveti olmayan kesirler (0,1) ikilide sonlu değildir.
  • DIV BX DX:AX'i böler, bölümü AX'e, kalanı DX'e yazar; DX önceden sıfırlanmalıdır. SHR 2'ye böler ve kalanı CF'ye düşürür; RCR CF'yi bir yazmaca taşır.
  • Bit deseni anlam taşımaz; yorumu program verir. İkiye tümleyende −x = NOT x + 1 = 2n − x'tir; NEG bunu tek komutta yapar. MSB işaret bitidir; tek bir sıfır vardır; 8 bitte aralık −128 … +127'dir. Birler tümleyeninde (NOT) ve işaret-büyüklükte iki sıfır bulunur.
  • İşaret genişletme üst bitlere işaret bitini kopyalar (CBW, CWD): −5 = FBh = FFFBh. Sabit noktalı sayılarda virgülün yeri programcının kabulüdür; toplama sıradan tamsayı toplamasıdır.
  • İkili toplama tam toplayıcılarla yapılır; çıkarma, ikiye tümleyenle toplamaya çevrilir. Onaltılıkta sütun toplamı 16'ya ulaşınca elde oluşur; 15'e ve 16'ya tümleyen, birler ve ikiye tümleyenin karşılığıdır.
  • CF işaretsiz yorumda sonucun sığmadığını (elde ya da ödünç), OF işaretli yorumda sığmadığını gösterir. OF yalnız aynı işaretli sayılar toplanırken ya da farklı işaretli sayılar çıkarılırken 1 olabilir; donanım, işaret bitine giren ve çıkan eldeyi karşılaştırır.
  • Bitler devrede gerilim düzeyleridir; eşik aralıkları gürültü payı sağlar. Flip-flop bir bit saklar; SR'de S = R = 1 yasaktır, JK'de J = K = 1 tersler. Yazmaçlar, saatin yükselen kenarında yüklenen D flip-flop'lardan kurulur.
  • IEEE 754 tek duyarlıklı sayı 1 işaret, 8 üs (127 kaydırmalı) ve 23 kesir bitinden oluşur; değer (−1)s × 1,f × 2e−127'dir. 8086'nın kayan nokta komutu yoktur; bu iş 8087'ye ya da yazılıma kalır.
  • BCD her onluk basamağı dört bitle tutar; toplamadan sonra geçersiz basamağa ya da AF = 1 ise 6 eklenir (DAA). 8086 little-endian'dır: düşük bayt düşük adrestedir. Gray kodunda ardışık değerler tek bitte farklıdır: G = B ⊕ (B >> 1).

1.2.12Kavram listesi

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

1.2.13Kendini Dene

  1. 300 sayısını onaltılık ve ikili olarak yazın. Bu değer AL'ye sığar mı?

    Cevap

    300 ÷ 16 = 18, kalan 12 (C); 18 ÷ 16 = 1, kalan 2; 1 ÷ 16 = 0, kalan 1. Sonuç 12Ch'dir; rakamlar 4 bite açılınca 1 0010 1100b bulunur. Değer 255'ten büyük olduğu için 8 bitlik AL'ye sığmaz; dokuz bit gerekir. AX'e sığar.

  2. 0,3125 sayısını ikiliye çevirin. Sonuç sonlu mudur? Neden?

    Cevap

    0,3125 × 2 = 0,625 → 0; 0,625 × 2 = 1,25 → 1; 0,25 × 2 = 0,5 → 0; 0,5 × 2 = 1,0 → 1. Bitler yukarıdan aşağı okununca 0,0101b çıkar: 1/4 + 1/16 = 0,3125. Sonuç sonludur, çünkü 0,3125 = 5/16 ve payda 2'nin kuvvetidir.

  3. 1101 0110b deseninin işaretsiz, ikiye tümleyen ve birler tümleyeni yorumları nedir?

    Cevap

    İşaretsiz: 128 + 64 + 16 + 4 + 2 = 214. İkiye tümleyen: 214 − 256 = −42 (ya da ağırlıklarla −128 + 64 + 16 + 4 + 2 = −42). Birler tümleyeni: bitler ters çevrilince 0010 1001 = 41 çıkar; yorum −41'dir.

  4. AL = 80h iken CBW çalışıyor. AX ne olur? Aynı değer sıfırla genişletilseydi ne bulunurdu?

    Cevap

    AL'nin MSB'si 1'dir; CBW AH'yi FFh yapar ve AX = FF80h olur. Bu, 16 bitte −128'dir (65 536 − 128 = 65 408 = FF80h). Sıfırla genişletme 0080h = +128 verirdi; işaretli değer korunmazdı.

  5. AL = 7Fh iken ADD AL, 1 çalışıyor. AL, CF, OF, SF ve ZF ne olur? Sonucu işaretsiz ve işaretli yorumlayın.

    Cevap

    0111 1111 + 1 = 1000 0000, yani AL = 80h. En üst bitten elde çıkmaz: CF = 0. İşaret bitine elde girer ama çıkmaz: OF = 1. SF = 1, ZF = 0. İşaretsiz yorumda 127 + 1 = 128 doğrudur; işaretli yorumda +127 + 1 sonucu −128 olarak görünür ve taşmadır. Sayı çemberinde 0111'den 1000'e geçişin 8 bitlik karşılığıdır.

  6. Q5.3 biçimindeki F4h hangi değeri gösterir?

    Cevap

    F4h = 11110,100b. Ağırlıklarla −16 + 8 + 4 + 2 + ½ = −1,5. Kısa yol: F4h = 244, işaretli olarak 244 − 256 = −12; −12 / 8 = −1,5.

  7. 0,75 sayısını 32 bitlik IEEE 754 biçiminde yazın.

    Cevap

    0,75 = 0,11b = 1,1b × 2−1. İşaret 0; üs −1 + 127 = 126 = 0111 1110b; kesir 1000…0. Desen 0 01111110 10000000000000000000000 = 0011 1111 0100 0000 … = 3F400000h.

  8. AL = 66h ve BL = 57h paketli BCD sayılardır. ADD AL, BL ve ardından DAA çalışınca AL ve CF ne olur?

    Cevap

    İkili toplam 66h + 57h = BDh'dir. Düşük nibble D (13) geçersizdir: 6 eklenir, C3h olur. Yüksek nibble C (12) de geçersizdir: 60h eklenir, 123h olur. AL = 23h, CF = 1. Sonuç BCD 123'tür: 66 + 57 = 123; yüzler basamağı CF'dedir.

  9. DS:0200h'den başlayarak DW 1234h, 0ABCDh tanımlanmış. MOV AX, [0201h] sonrası AX nedir?

    Cevap

    Little-endian düzende baytlar 0200h: 34h, 0201h: 12h, 0202h: CDh, 0203h: ABh'dir. AL, 0201h'den (12h), AH, 0202h'den (CDh) yüklenir: AX = CD12h. Okuma tek adresten başladığı için iki yol döngüsü sürer.

  10. Gray kodu 1001 olan 4 bitlik sayının ikili karşılığı nedir? Sonucu formülle sağlayın.

    Cevap

    B3 = G3 = 1; B2 = 1 ⊕ 0 = 1; B1 = 1 ⊕ 0 = 1; B0 = 1 ⊕ 1 = 0. İkili karşılık 1110 = 14'tür. Sağlama: 1110 ⊕ 0111 = 1001.

1.2.14İleri okuma

  • M. M. Mano ve M. D. Ciletti, Digital Design (5. baskı), Bölüm 1, 4 ve 5: sayı sistemleri, tümleyenler, BCD ve Gray kodu ile toplayıcı devreler ve flip-flop'lar, sayısal tasarım bakış açısından ayrıntılı ele alınır.
  • B. B. Brey, The Intel Microprocessors (8. baskı), Bölüm 1: sayı sistemleri, işaretli sayılar, BCD ve bayt sıralaması doğrudan 8086 ailesinin veri biçimleriyle ilişkilendirilir.
  • D. Goldberg, “What Every Computer Scientist Should Know About Floating-Point Arithmetic”, ACM Computing Surveys, 23(1), 1991: IEEE 754'ün yuvarlama, özel değerler ve hata birikimi konularını açıklayan klasik makaledir.
  • D. E. Knuth, The Art of Computer Programming, Vol. 2: Seminumerical Algorithms, Kesim 4.1: konumsal sayı sistemlerinin tarihini ve taban dönüşümü yöntemlerini kanıtlarıyla verir.

1.2.15Kaynaklar

  1. M. Morris Mano, Michael D. Ciletti, Digital Design, 5. baskı, Pearson, 2013.
  2. Barry B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009, Bölüm 1.
  3. IEEE Std 754-2019, IEEE Standard for Floating-Point Arithmetic.
  4. emu8086 belgeleri, Numbering systems tutorial.
  5. Mehmet Bodur, Mikroişlemcilere Giriş: Assembler ile Yazılım ve Arayüz, EMO, 2014.
  6. Şadi Çağatay Öztürk, Oğuz Ergin, Intel 8086 ile Mikroişlemci Programlamaya Giriş, 2009.
  7. David Goldberg, “What Every Computer Scientist Should Know About Floating-Point Arithmetic”, ACM Computing Surveys, 23(1):5–48, 1991.
  8. Donald E. Knuth, The Art of Computer Programming, Vol. 2: Seminumerical Algorithms, 3. baskı, Addison-Wesley, 1997.

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