Komut kümesi mimarisi

**Komut kümesi mimarisi** ( veya kısaca *ISA*), CPU'nun yazılım tarafından nasıl kontrol edileceğini tanımlayan bilgisayar soyut modelinin bir parçasıdır. ISA, işlemcinin ne yapabileceğini ve bunu nasıl yapacağını belirterek donanım ve yazılım arasında bir arayüz gibi davranır.

**[[Bilgisayar mimarisi]]**, Donanım Sistemi Mimarisi (*hardware system archıtecture*, HSA) ve ISA başlıkları altında tanımlanır. HSA donanım aygıtlarının (G/Ç, Bellek, CPU vs.) bağlı olduğu altsistemi oluşturur. ISA ise bu bileşenlere yön verecek programlar yazılırken kabul edilecek öngörülerdir. Dolayısıyla ISA yazılım ile donanım arasında iş gören bir birimdir.

Merkezi işlem birimine yön verecek program bazı adımlardan oluşur. Bu adımlara işlem kodu (opcode) denir ve CPU'ya yapacağı işlemin hangi büyüklükler üzerinde olacağı belirtir. Yapılacak işlemi ve adresleme yöntemini belirten ise komuttur. İşlenen, üzerinde işlem yapılacak büyüklüğü ya da büyüklüğün yerini (bellek gözünü) belirtir.

Yüksek seviye diller bilgisayar mimarisinden bağımsızdır. Bu diller derleyici tarafından mimariye bağımlı olan makine diline çevrilir. Assembler, bu çevrilen makine dili komutlarını çalıştırılabilir ikili (binary) kodlara çevirir. ISA işlemcinin programcıya görünen yüzüdür. Yüksek seviye diller mimari detaylarını programcıdan saklar.

## Komut yapıları
Bir işlem kodu bir komut ve bir veya daha fazla işlenenden oluşur. Komut kümesini kodlamak farklı yöntemlerle yapılabilir. Mimariler, komut başına içerilen bit sayısından (genellikle 16, 32 ve 64 bit), komut başına içerilen işlenen sayısından, komut türlerinden ve her birinin işleyebileceği verilerden dolayı birbirlerinden farklılık gösterir:

* Merkezi işlem birimi içinde işlenenlerin saklanacağı hafıza (storage)
İşlenenler bellek dışında nerede saklanacak? Veriler yığın (stack) veya yazmaç içinde saklanabilir.

* Komut başına belirgin işlenen (operand) sayısı
Bir komutta kaç işlenen isimlendirilecek? 0, 1, 2, 3 en yaygın işlenen sayılarıdır.

* İşlenen konumu
Herhangi bir AMB komut işleneni bellekte konumlanabilir mi? Yoksa bütün işlenenler CPU içerisinde mi tutulacak? Komutlar yazmaçtan-yazmaca, yazmaçtan-belleğe ya da bellekten-belleğe gibi komut başına işlenenlerin kombinasyonu şeklinde sınıflandırılabilir.

* İşlemler
ISA ne gibi işlemleri destekleyecek? Ayrıca hangi komutlar belleğe erişecek ve hangileri erişmeyecek?

* İşlenenlerin türü ve boyutu
İşlenenlerin türü ve boyutu ne olacak ve nasıl belirtilecek? Bir işlenen, adres, numara ve hatta karakter olabilir.

Bütün bunların içerisinde en önemli farklılık CPU içerisinde işlenenleri saklayacak ara hafıza birimleridir.

Komutlar; etiket alanı, işlem kodu alanı, işlenen alanı ve yorum satırından oluşur. Bunlara Kaynak Program Alanları denir.

Etiket alanı bir sayısal değere veya bir bellek alanına karşılık gelir. Yazılması isteğe bağlıdır. Herhangi bir BRANCH, JUMP veya CALL komutunun altyordama dalış adresi olabilir. Etiketlerin kullanılma sebepleri:

* Program alanlarının bulunmasında ve hatırlanmasında kolaylık sağlaması
* Programda yapılan bir değişiklikte veya düzenlemede kolayca hareket ettirilebilmesi
* Programa yeniden yerleştirme sabiti eklenerek assembler ve yükleyici her bir adrese yeniden yüklenebilmesi

İşlem kodu alanında mnemonic (hatırlatıcı) harflerle yazılan yapılacak işin komutları bulunur.

Mesela "LoaD Accumulator with operand" komutu LDA, "Branch on Carry Set" komutu BCS şeklinde kısaltılmıştır.

İşlenen alanı işlenene gerek duyan komutların veri veya adres tanımladıkları yerdir. İşlenenin başına veya sonuna konulan işaretlerden ne tür bir bilgi olduğu anlaşılır. Tabloda bu işaretler anlamlarıyla birlikte gösterilmiştir:

Yorum satırı programcı tarafından bir başkasının programı anlaması amacıyla konulmuştur ve isteğe bağlıdır. Program satırlarında komutların ne yaptığını anlatmak için kullanılır. Derleyici tarafından dikkate alınmaz.

### Komut kümeleri için tasarım kararları
Bir bilgisayar mimarisi, tasarım aşamasında öncelikli olarak bir komut kümesi formatı belirlemelidir. Bu formatı seçmek genellikle oldukça zordur zira komut kümesi mimariyle uyuşmalıdır ve mimari, ömrünü yıllarca sürdürebilmelidir. Tasarım aşamasında yapılan kararlar uzun süreli dallanmalara sahiptir.

Komut kümesi mimarisi bazı faktörlere göre ölçülür, bunlar:

# bir program için gereken alan, 
# bir komutu yürütmek için gereken çözümleme sayısı cinsinden komut kümesinin karışıklığı ve komut tarafından yürütülen görevlerin, işlerin karışıklığı, 
# komutların uzunlukları,
# toplam komut sayısı.

Bir komut kümesi tasarlanırken göz önünde bulundurulması gerekenler ise:

* Kısa komutlar tipik olarak daha iyidir çünkü bellekte daha az yer kaplar ve daha hızlı yakalanır. Ancak bu komut sayısını kısıtlar çünkü ihtiyacımız olan komutların sayısını belirtmek için komut içinde yeterli sayıda bit olması gerekir. Kısa komutlar ayrıca boyut ve işlenen sayısı üzerinde de daha sıkı kısıtlamalara sahiptir.
* Uzunlukları sabit komutları çözümlemek daha kolaydır fakat bu alan israfına yol açar.
* Bellek organizasyonu komut yapısını etkiler. Mesela eğer bellekte 16 veya 32 bitlik sözcükler varsa ve bellek baytla adreslenebilir değilse basit bir karaktere ulaşmak zordur. Bu sebepten dolayı 16, 32 veya 64 bitlik sözcüklere sahip olan makineler bayt adreslenebilir olsalar bile ve sözcükler 1 baytdan büyük olsalar dahi her bir bayt tek bir adrese sahiptir.
* Sabit uzunluktaki bir komut belirli sayıda işlenene sahip olmayabilir. Buyruğun bütünü açısından sabit uzunlukta komut tasarlayabilmemiz gerekir, fakat işlenen kısmındaki bitler gerektiği zaman değişebilmeli (buna genişletilmiş işlem kodu denir).
* Çok değişik sayıda adresleme türü vardır.
* Eğer baytlar katlı sayıda baytlardan oluşuyorsa, bu baytlar baytla adreslenebilir bir makinede nasıl sıralanırlar? En önemsiz bayt en yüksek bayt adresinde mi yoksa en düşük bayt adresinde mi saklanmalı? Burada soldan ve sağdan anlamlı bellek adresleri devreye girer (endianness).
* Mimari ne kadar yazmaç içerecek ve bu yazmaçlar nasıl organize olacak? İşlenenler CPU'da nasıl saklanacak?

### Soldan ve sağdan anlamlılık
Soldan anlamlılık (big endian) ve sağdan anlamlılık (little endian) çok baytlı verinin bellekte nasıl dizileceği ilgili kavramlardır. Çoğu mimari bayt-adreslenebilir olduklarından çok sayıda baytın bellekte nasıl sıralanacağıyla ilgili bir standarda sahip olmalıdır.

Sıralanmış bir sözcükte en büyük baytın (most significant byte, MSB) adresi, o sözcüğün adresi ise bu sıralamaya soldan anlamlı denir. UNIX makinelerinin çoğu soldan anlamlıdır (IBM 360/370, Motorola 68k, MIPS, Sparc, HP PA).

Eğer en küçük baytın (least significant byte, LSB) adresi sözcük adresine eşitse, bu sıralanmaya sağdan anlamlı denir. PC'lerin çoğu sağdan anlamlıdır (Intel 80x86, DEC Vax, DEC Alpha).

İşlemci üreticileri bu konuda iki gruba ayrılır. Örneğin, Motorola devamlı soldan anlamlılığı kullanırken Intel sağdan anlamlılığı kullanlır.

4 baytlık bir tam sayı:
Bayt3 Bayt2 Bayt1 Bayt0

Soldan anlamlı bir makinede:
Taban Adresi + 0 = Bayt3
Taban Adresi + 1 = Bayt2
Taban Adresi + 2 = Bayt1
Taban Adresi + 3 = Bayt0

Sağdan anlamlı bir makinede:
Taban Adresi + 0 = Bayt0
Taban Adresi + 1 = Bayt1
Taban Adresi + 2 = Bayt2
Taban Adresi + 3 = Bayt3

şeklinde sıralanır. Bayt adreslenebilir bir makinede 32-bit onaltılı 0x5FA1B2C3 değerinin 0x1A2B3C50 adresinde depolandığını varsayıldığında, bellekte şu şekilde görünür:

Her iki yöntemin de avantajları ve dezavantajları bulunur. Soldan anlamlı insanlara alışıldık gelir, bu yüzden özellikle yığınları okuması daha kolaydır. Yüksek seviyedeki baytın önce gelmesi sebebiyle ofset sıfırdaki bayta bakarak her zaman sayının pozitif veya negatif olduğu bulunabilir (sağdan anlamlıda işareti belirlemek için sayının uzunluğu bilinmelidir ve işaret bilgisini içeren bayt bulunmalıdır). Soldan anlamlı makineler tam sayıları ve dizileri aynı şekilde sıralar ve dizi işlemlerinde daha hızlıdır. Çoğu bit eşli grafikler "en anlamlı bit soldaki" ilkesine göre eşlenmiştir. Bu durum sağdan anlamlı makineler için bir performans kısıtlaması getirir çünkü bir baytdan daha büyük grafik elemanlarıyla çalışırken sürekli baytların sırasını ters çevirmek zorundadır.

Ancak soldan anlamlılığın dezavantajları da vardır. 32 bit tam sayı adresinden 16 bit tam sayı adresine çeviride toplama yapmak için sağdan anlamlı bir makine gereklidir. Yüksek kesinlikte aritmetik işlemler sağdan anlamlılık kullanarak daha kolay ve hızlıdır. Soldan anlamlılığı kullanan çoğu mimari sözcüklere adreslenemeyen alanlara sözcüklerin yazılmasına izin vermez (örneğin eğer sözcük 2 veya 4 baytsa adres her zaman çift sayı olmak zorundadır). Bu boşluk bellek israfına sebep olur. Sağdan anlamlı mimariler, Intel gibi, tek sayılı adreslerin okunup yazılmasına izin verir. Bu yüzden bu makineler üzerinde programlama daha kolaydır.

Bilgisayar ağları soldan anlamlıdır. Sağdan anlamlı bilgisayarlar ağ üzerinden tam sayıları geçirecekleri zaman bunları ağ bayt sıralamasına çevirmek zorundadırlar. Aynı şekilde, tam sayıları alacakları zaman kendi ifadelerine çevirmek zorundadır.

Yazılım uygulamaları açısından soldan ve sağdan anlamlılık son derece önemlidir. Bir dosyadan veri okuyacak veya veri yazacak olan herhangi bir program makinenin bayt sıralamasına göre hareket etmelidir. Soldan anlamlı bir makinede sağdan anlamlılığı kullanan bir programı açmak için öncelikli olarak bayt sıralaması tersine çevrilmelidir. Mesela Adobe Photoshop, JPEG, MacPaint ve Sun raster dosyaları soldan anlamlı, GIF, PC Paint brush, RTF (Microsoft tarafından) sağdan anlamlıdırlar. Microsoft WAV ve AVI dosyaları, TIFF dosyaları, XWD ise her iki sıralamayı destekler.

### CPU içerisinde dahili depolama birimleri: yığınlar (stacks) ve yazmaçlar (registers)
Bir kez hafızadaki bayt düzeni belirlendiğinde donanım tasarımcısı CPU'nun veriyi nasıl depolayacağına dair bazı kararlar vermek zorundadır. Bu, en basit anlamda komut kümesi mimarisine karar vermektir. Üç seçenek vardır:

# Bir yığın tabanlı mimari
# Bir biriktirici tabanlı mimari
# Bir genel amaçlı yazmaç (GPR - general purpose register) mimarisi

Yığın mimarisinin komutlarını işletmek için bir yığın kullanır ve işlenenler yığının en üstüne aşağıdan yukarı doğru dizilir. Yığın yapılı makineler iyi bir kod yoğunluğuna ve ifadelerin değerlendirilmesi için sade bir modele sahip olmalarına rağmen, istenilen bir yığına rastgele erişilemez, bu nedenle yığınlı yapılarda etkili kod oluşturulması zordur. 
 
Bir işlenenin tamamı biriktiricinin içinde olan biriktirici mimarileri, makinenin karmaşıklığını en aza indirir ve çok kısa komutlara izin verir. Ancak biriktirici yalnız geçici depolama yaptığından hafıza trafiği (erişimi) oldukça yüksektir. 
 
Genel amaçlı yazmaç kullanan mimariler, günümüzün makine mimarileri içerisinde en çok tercih edilen modelidir. Bu yazmaç kümeleri bellekten çok daha hızlıdır, derleyici tarafından kullanılması çok kolay, çok etkin ve çok verimlidir. Ayrıca son yıllarda donanım fiyatları önemli ölçüde düştü ve böylece en az maliyetle çok sayıda yazmaç eklenebilir oldu. Eğer bellek erişimi hızlı ise, yığın tabanlı tasarım iyi bir seçenek olabilir. Bellek erişimi yavaşsa, yazmaçları kullanmak çok daha iyidir. Bu sebeple son 15 yılda çıkan pek çok bilgisayar sistemleri genel yazmaç tabanlıdır. Uzun komutlarda tüm işlenenler yazmaçların sonuçları kullanılarak isimlendirilmelidir, bu sebeple daha uzun getirme, yakalama ve çözme zamanları ve döngüleri oluşur. (Kısa komutlar ISA tasarımcıları için çok önemli bir amaçtır.) Tasarımın ISA seçimi aşamasında tasarımcılar belirli bir ortamda en iyi hangi mimarinin çalışacağına karar vermeli ve vazgeçilecek (taviz verilecek) şeyleri dikkatle tetkik etmelidirler. (İyi tasarım fedakârlık gerektirir).

Genel amaçlı mimari, işlenenlerin bulundukları yerlere göre üçe ayrılabilir. Bellek-bellek mimarilerinde bellekte iki ya da üç işlenen birlikte bulunur. Böylece bir yazmaçta herhangi bir işlenene ihtiyaç duyulmadan komutun işlem yapmasına izin verilir. Yazmaç-bellek mimarileri en az bir işlenenin yazmaçta, bir işlenenin de bellekte olmasını gerektiren bir yapıya ihtiyaç duyar. Yükle depola mimarileri veri üzerinde herhangi bir işlem yapılmadan önce verinin yazmaçlara gönderilmesini sağlar. Intel ve Motorola yazmaç bellek mimarilerine örnektir; Digital Equipment'in VAX mimarisi bellek-bellek işlemlerine izin verir; MIPS, SPARC, PowerPC ve ALPHA yükle-depola makinelerine örneklerdir. 
 
Günümüzde birçok mimari GPR tabanlıdır. Şimdi GPR mimarilerini ikiye bölen ana komut kümesi karakteristiklerini inceleyelim. Bunlar adresleme biçimleri ve işlenenlerin sayıları olarak iki grupta incelenirler.

### İşlenen sayıları ve komut uzunluğu
Bir bilgisayar mimarisini tanımlamak için en bilindik yöntem her bir komutta yer alan en fazla işlenen sayısını ya da adresini belirlemektir. Bu tek başına komutun uzunluğuna doğrudan etki etmektedir. Güncel mimarilerdeki komutlar iki şekilde biçimlendirilebilir:

* Sabit Uzunluk: Alanı boş yere israf eder, ancak komut-seviyesi boru hattı kullanıldığında hızlıdır ve daha iyi performans oluşur.
* Değişken Uzunluk: Şifre çözmesi daha karmaşıktır fakat depolama alanını en iyi şekilde kullanılır.

Çoğu zaman, gerçek hayatta uzlaşma, kolay görülebilen ve kod çözümü daha kolay olan bit kalıplarını sağlayan iki-üç komut uzunluğunu kullanmayı gerektirir. Komut uzunluğunu makinedeki sözcük uzunluğuyla karşılaştırmamak lazım. Eğer komut uzunluğu sözcük uzunluğuna eşitse, komutlar ana bellekte saklandıklarında mükemmel bir şekilde hizalanırlar. Komutlar, adreslemeden dolayı daima hizalanmalıdır. Bundan dolayı, bir sözcüğün iki katı, üç katı, yarısı ya da çeyreği büyüklüğündeki komutlar boşa alan israf edebilir. Değişken uzunluktaki komutlar aynı boyutta olmadıklarından hizalanmaları gerekir, bu da yine alan israfına yol açar. 
 
En yaygın komut biçimleri sıfır, bir, iki ya da üç işlenene sahip olanlardır. Mantık ve aritmetik işlemleri genellikle iki işlenene sahiptir, ancak eğer biriktirici (accumulator) varsa işlemler yalnızca bir işlenenle yürütülebilir. Bu yaklaşımı üç işlenene genişletirsek son hedef üçüncü işlenen olacaktır. Ayrıca yığın yapısı kullanılarak sıfır işlenenli komutlar oluşturulabilir. Aşağıdakiler en genel komut biçimleridir:

* Sadece işlem kodu (adres yok) 
* İşlem kodu + 1 Adres (genellikle bir bellek adresi) 
* İşlem kodu + 2 Adres (genellikle iki yazmaç ya da bir yazmaç bir bellek adresi) 
* İşlem kodu + 3 Adres (genellikle üç yazmaç ya da yazmaç ve belleğin bileşimi)

Mesela MIPS mimarisinde aşağıdaki komut biçimleri kullanılır:

Bütün mimariler komut başına işlenen sayısında izin verilen bir sınıra sahiptir. Sıfır, bir, iki ve üç işlenenli komutların çok yaygın olduğunu söylemiştik. Bir, iki ve üç işlenenli komutları anlamak kolaydır, ancak tamamıyla sıfır işlenenli komutlar üzerine yapılmış bir komut kümesi mimarisi bir hayli karmaşıktır. 
 
Toplama gibi, mantık olarak bir ya da iki işlenene ihtiyaç duyan işlemlerin yapılabilmesi için işleneni olmayan makine komutları yığın kullanmaya ihtiyaç duyar. Yığın tabanlı mimari genel amaçlı yazmaçları kullanmak yerine işlenenleri yığının en üstünde saklar ve en üstteki ögeye merkezi işlem biriminin ulaşmasını sağlar. (Makine mimarilerindeki en önemli veri yapılarından biri yığındır. Yığın yapısı karmaşık hesaplamalar sırasında ara değerleri verimli bir şekilde saklar, yordam çağrıldığı anda parametrelerin geçişini verimli bir şekilde sağlar, bununla birlikte yerel blok yapısının korunmasını da sağlar, değişkenlerin ve altyordamların kapsamlarını belirler.)
 
Yığın tabanlı mimarilerde, birçok komut yalnızca işlem kodlarından oluşur. Bununla birlikte sadece bir işleneni olan özel komutlar da vardır (yığına eleman ekleyen veya yığından eleman çıkaran tipi komutlar). Yığın mimarileri, her biri bir işlenene sahip olan push ve pop komutlarına ihtiyaç duyarlar. Push X komutu, X bellek konumundaki veri değerini yığının üstüne yerleştirir. Pop X komutu, yığının en üstteki ögesini siler ve X bellek konumuna yazar. Belleğe erişme izni sadece bazı komutlara verilir; diğer bütün komutlar yürütme esnasında herhangi bir işlenen için yığını kullanmak zorundadır. 
 
İki işlenene ihtiyaç duyulan işlemlerde, yığının en üstteki iki elemanı kullanılır. Mesela bir ADD komutu çalıştırıldığında, CPU yığının en üstteki iki elemanını alır, ikisini de yığından atar ve yığının en üstüne toplama işleminin sonucunu yerleştirir. Çıkarma işlemi gibi değişmeli olmayan işlemlerde, en üstteki öge bir altındaki ögeden çıkarılır, ikisi de yığından atılır ve yığının en üstüne çıkarma işleminin sonucu yerleştirilir. 
 
Bu yığın organizasyonuna Reverse Polish Notation (RPN) veya postfix gösterimi denir ve uzun aritmetik ifadeler için oldukça etkili ve verimlidir. Postfix gösteriminde, işleç işlenenlerden sonra yer alır. Infix gösteriminde işleç işlenenlerin arasında yer alır, prefix gösteriminde ise işleç işlenenlerden önce gelir:

* X Y + postfix (Reverse Polish)
* X + Y infix
* + X Y prefix (Polish)

gösterimidir.

Bütün aritmetik ifadelerin bu gösterimleri kullanarak yazılması mümkündür. Fakat, bir yazmaç yığını ile birleştirilmiş postfix gösterimi, aritmetik ifadelerin hesaplanmasında en etkili yoldur. Bazı elektronik hesap makineleri kullanıcıdan ögeleri postfix gösteriminde girmesini ister. Bu hesap makinelerinde biraz alıştırma yapıldığında, iç içe dizilmiş birçok parantez içeren uzun ifadeleri, terimlerin nasıl gruplandığını bile düşünmeden, daha hızlı bir şekilde hesaplamak mümkündür.

(X + Y) x (W - Z) + 2

Denklemi RPN'de yazılırsa aşağıdaki gibi olur:

XY + WZ - x2+

Dikkat edilecek olursa, RPN'de öncelikleri korumak amacıyla kullanılan parantezlere ihtiyaç duyulmaz.

Sıfır, bir, iki ve üç işlenen kavramlarıyla ilgili bir örnek verelim. Her bir kavramı kullanarak, bir aritmetik hesap yapan basit bir program yazalım.

Örnek, aşağıdaki ifadeyi hesaplansın:

Z = (X x Y) + (W x U)

Genelde, üç işlenene izin verildiğinde, en az bir işlenen yazmaç olur ve ilk işlenen genellikle hedef olur. Üç adresli komutları kullanırken, Z'nin hesaplanması için gereken kodu aşağıdaki gibi yazabiliriz:

```asm
Mult R1, X, Y
Mult R2, W, U
Add Z, R2, R1
```

Eğer iki adresli komutlar kullanılıyorsa, bir adres genellikle bir yazmacı ifade eder (iki adresli komutlar iki işlenenin de bellek adresi olmasına pek izin vermez). Diğer işlenen, bir yazmaç ya da bir bellek adresi olabilir. İki adresli komutlar kullanırsak kodumuz aşağıdaki gibi olur:


```asm
Load R1, X
Mult R1, Y
Load R2, W
Mult R2, U
Add R1, R2
Store Z, R1
```


İlk işlenenin hedef mi yoksa kaynak mı olduğunu bilmek önemlidir, burada hedef olduğunu öngörüyoruz. (Bu noktada, Intel çevirici dili ile Motorola çevirici dili arasında geçiş yapmak zorunda kalan programcıların kafası karışabilir. Çünkü Intel çeviricisi ilk işleneni hedef alır, Motorola çeviricisi ise ilk işleneni kaynak alır.) 
 
Tek adresli komutlar kullanıldığında, bir yazmaç (genellikle biriktirici) komutun sonucu için hedef olarak gösterilir. Z'nin hesaplanmasındaki kod aşağıdaki gibi olur:

```asm
Load X 
Mult Y 
Store Temp 
Load W 
Mult U 
Add Temp 
Store Z
```

Komut başına izin verilen işlenen sayısı azaldı, fakat kodu çalıştırmak için gerekli olan komut sayısı arttı. Bu durum, mimari tasarımında tipik bir boşluk ya da zamandan taviz verme örneğidir. Daha kısa komutlar oluşur, fakat programlar uzar. 
 
Sıfır adresli komutlara sahip olan yığın tabanlı bir makinede bu programın ne yaptığını araştıralım şimdi de. Yığın tabanlı mimariler Add, Subt, Mult veya Divide komutları için işlenen kullanmazlar. Bir yığına ve bu yığında pop ve push işlemlerine ihtiyaç duyulur. Yığına erişim gerçekleştiren işlemler, işlenenin yığına eklendiğini ya da yığından çıkarıldığını belirten bir adres alanına sahip olmalıdırlar (diğer bütün işlemler sıfır adreslidir). Push komutu işleneni yığının en üstüne iter. Pop komutu yığının en üstündeki elemanı yakalar ve işlenene yerleştirir. Bu mimari, Z'yi hesaplayacak olan programın çok uzun olmasına sebep olur. Aritmetik işlemlerin yığının en tepesindeki iki işleneni kullandığını, onları yığından çıkardığını ve daha sonra işlemin sonucunu yığının en tepesine eklediğini öngörelim, kod aşağıdaki gibi oluşur:

```asm
Push X 
Push Y 
Mult 
Push W 
Push U 
Mult 
Add 
Store Z
```

Komutun uzunluğu, işlem kodunun uzunluğundan ve izin verilen işlenen sayısından etkilendiği yukarıda vurgulandı. İşlem kodunun uzunluğu sabit olduğunda, çözme işlemi çok daha kolay olur. Fakat geriye dönük uyumluluk ve esneklik sağlayabilmek için, işlem kodunun uzunluğu değişken olabilir. Değişken uzunluktaki işlem kodlarında, değişken uzunluktaki komutlarda görülen problemlere benzer sorunlar söz konusu olabilir. Birçok tasarımcı işlem kodlarını genişletme konusunda uzlaşmaya varmıştır.

### İşlem Kodlarını Genişletme
İşlem kodlarını genişletme, işlem kodlarının geniş bir kümesini ve kısa işlem kodları, dolayısıyla kısa komutları elde etme amacıyla ortaya çıkmıştır. Amacı bazı işlem kodlarını kısaltmak, ancak ihtiyaç olduğunda uzun işlem kodları da sağlamaktır. İşlem kodu kısa olduğunda, bitlerden birçoğu işlenenleri tutar (komut başına iki ya da üç işlenen bulunabilirdi). İşlenenler için alana ihtiyaç duyulmadığında (Halt gibi bir işlem sırasında ya da makine bir yığın kullandığında), tüm bitler işlem kodu için ayrılabilir, bu durum birçok benzersiz komuta izin verir. Az işleneni olan uzun işlem kodları olduğu gibi çok işleneni olan kısa işlem kodları da mevcuttur. 
 
16-bit komutlara ve 16 yazmaca sahip olan bir makine düşünelim. Bu kez basit bir ya da iki biriktirici yerine bir yazmaç kümesi bulunur, benzersiz bir yazmaç tanımlamak için 4 bit kullanırız. Her biri 3 yazmaç işlenenine sahip olan ya da işlem kodu için 4 bit, bellek adresi için 12 bit kullanan (4K boyutunda bir bellek olduğunu varsayıyoruz) 16 komutu şifreleyebiliriz. Bellek kaynağı 12 bite gereksinim duyar, diğer amaçlar için 4 bit kalır. Fakat, eğer bellekteki bütün veri ilk olarak bu yazmaç kümesindeki bir yazmaca yüklenirse, komut yalnızca 4 bit kullanarak (16 yazmaç olduğunu varsayarsak) gerekli veri ögesini seçebilir. Bu iki seçim aşağıdaki şekilde gösteriliyor;

Şekil: 16-bit komut biçimi için iki olasılık

Aşağıdaki komutları şifrelemek istediğimizi varsayalım;

* 3 adresli 15 komut
* 2 adresli 14 komut 
* 1 adresli 31 komut 
* 0 adresli 16 komut

Bu komut kümesini 16 bitle şifreleyebilir miyiz? İşlem kodlarını genişletme işlemini kullandığımız sürece cevap “evet” olur. Şifreleme aşağıdaki gibi yapılır;Genişleyen işlem kodu yapısı, çözme işlemini daha karmaşık hale getirir. Basit şekilde bir bit kalıbına bakıp hangi komut olduğuna karar vermek yerine, komutu aşağıda belirtildiği gibi çözmemiz gerekir:

```
if (leftmost four bits != 1111)
  (Execute appropriate three-address instruction)

else if (leftmost seven bits != 1111 111)
  (Execute appropriate two-address instruction)

else if (leftmost twelve bits != 1111 1111 1111)
  (Execute appropriate one-address instruction)

else 
  (Execute appropriate zero-address instruction)
```


Her adımda, daha fazla bite bakmamız gerektiğini bildiren yedek bir kod bulunur. Bu durum, donanım tasarımcılarının sürekli karşılaştıkları taviz vermelerin (trade-off) diğer bir örneğidir. Burada işlem kodu alanı işlenen alanıyla yer değiştirmiş olur.

## Komut türleri
Birçok bilgisayar komutu veri üzerinde yürütülür, ancak yürütülmeyen komutlar da vardır. Bilgisayar üreticileri komutları aşağıdaki kategorilere ayırır: 
* Veri aktarımları
* Aritmetik işlemler
* Boolean
* Bit işleme (shift ve rotate komutlarıyla)
* Giriş/Çıkış
* Denetim aktarımı
* Özel amaç

### Veri aktarım komutları
Veri hareket komutları en sık kullanılan komut türlerinden birisidir. Veri bellekten yazmaçlara, yazmaçlardan yazmaçlara ve yazmaçlardan belleğe taşınabilir, birçok makine kaynak ve hedefe bağlı olarak farklı komutlar sağlar. Mesela bir MOVE komutu her zaman iki yazmaçlı işlenene ihtiyaç duyabilir, oysa MOVE komutu bir yazmaç ve bir bellek işlenine izin verir. RISC gibi bazı mimariler, işletimi hızlandırmak için belleğe veya bellekten veri taşıyan komutları sınırlandırır. Birçok makine, farklı boyutlardaki veriyi işlemek için değişik load, store ve move komutlarına sahiptir. Mesela bayt işlemek için bir LOADB komutu, sözcük işlemek için de bir LOADW komutunun kullanılması gibi. Bellekten belleğe doğrudan veri aktarım komutu yoktur. Bu durumda CPUgibi aracı elemana ihtiyaç duyulur. Veri önce bellekten biriktiriciye alınır, daha sonra da diğer bellek alanlarına aktarılır.
 
Veri aktarım işlemleri kendi arasında üç alt gruba ayrılırlar: Aktarım bellekle yazmaç arasında, yazmaçtan yazmaca ve yığına veri atıp geri alma şeklinde yapılabilir.

### Bellek-yazmaç aktarımı
Komutların sonunda bulunan harfler belirli kaydedicileri hedefler. Mesela A kaydedicisini, X indis kaydedicisini ve Y indis kaydedicisini hedefleyebilir. Verinin alındığı bellek konumları, komutun işlenen kısmında belirtilir. Bu adresler, indisli, mutlak ve veri tanımlı olabilirken, bayraklardan Z ve N bayrakları etkilenirler.

Kaydedicilerden belleğe depolama veya saklama yapmak için STA, STX ve STY komutları kullanılır. Bu kaydedicilerdeki bilgi işlenen üzerinden hedeflenen bellek konumuna aktarılır. Bu aktarım işlemleri sırasında bayraklarda bir değişme olmaz. Veri aktarım işlemlerinde kaynağın içeriği değişmez, fakat hedefin içeriği değişir.

Mesela belleğin bir konumundaki veri alınarak başka bir konumuna atılma işlemi için basit bir program yapılırsa:

```
LDA $0200  ; (Load to A), A = [$0200]
STA $2025  ; (Store the A), [$2025] = A
```


### Yazmaçtan yazmaca aktarım
Bu komutlar bellekte bir baytlık yer kaplarlar. Komut yanında işlenene gerek duyulmaz. Kaydediciden kaydediciye veri aktarım komutları; TAX, TAY, TXA, TYA, TSX ve TXS'dir.
 
Burada komutun ortasındaki harf daima kaynak kaydedicisini, sondaki harf ise hedef kaydedicisini gösteririr. TXS'nin dışında diğer komutlar N ve Z bayraklarını etkiler.
 
TXS komutu program başlangıcında yığın işaretçisini (stack pointer, SP) hazırlamada kullanılır. SP yığındaki bir sonra kullanılabilecek bellek konumunu gösterir.

```
LDX #$FF ; Yığının dibini gösterecek veriyi hazırla
TXS 	 ; ve yığın işaretçisine aktar.
```


### Veri aktarımları
Veri, biriktiriciden yığına, yığından biriktiriciye ve durum (P) bilgileri yığına, yığından tekrar duruma aktarılır. Yığına atılan bir veri, yığın işaretçisinin değerini bir azaltır, yığından geri çekilen bir veriyle de yığın işaretçisi tekrar bir artar.

Yığın kullanımı iki sebeple gerçekleştirilir:
* Kesmelere cevap vermek için ve altyordamlara dalmalarda dönüş adresini saklamak için
* Kaydedici içeriklerinin geçici olarak depolanması için.

Mesela 6502 mimarisinde, PHA komutu, yığın işaretçisinin gösterdiği ilk yığın konumuna biriktiricinin içeriğini atarken, yığın işaretçisi bir sonraki boş konumu göstermek için değerini bir azaltır:

```asm
0200 LDA #$A5 ; A=A5H
0202 PHA      ; A'yı yığına at
0203 LDA #$67 ; A=67H
0205 PHA      ; A'yı yığına at
```


### Aritmetik işlem komutları
Aritmetik işlemler tam sayıları ve kayan nokta sayılarını kullanan komutlara sahiptir. Komut kümelerinde çeşitli veri boyutları olduğundan farklı aritmetik komutlar bulunur. Veri aktarım komutlarıyla, değişik adresleme biçimlerinde yazmaç ve bellek erişiminin çeşitli kombinasyonlarını sağlamaya yarayan farklı komutlar olabilir.

#### Toplama işlemi
Sekiz adresleme biçimini kullanabilen ADC ve ADD komutları, işlenenin değerini, elde ile birlikle biriktiricideki sayıyla toplayarak yine sonucu biriktiriciye atar. Bu işlemin sembolik gösterimi şu şekildedir:

[A] = [A] + [M] + C
 
Buradaki [M], ADC ve ADD komutlarının işlenen kısımlarında bulunan veriyi veya bellekle bulunan bir veriyi göstermektedir. Toplama işlemi, durum bayrağındaki D'nin durumuna göre ikili sayı kodunda ya da BCD kodunda olabilir. Veriler toplama ve çıkarma işlemlerinde işaretli veya işaretsiz şekilde birlikte kullanılabilir. Programcının ne tür bir veri kullandığını bilmesi gerekir.

ADD komutu işlenirken bir önceki işlemden kalan elde varsa bu bi sonraki eldeye katılarak toplama işlemine sokulur. Toplama işlemine bir örnek verilirse:

```asm
CLC      ; C=0
LDA #$25 ; [A]=25H
ADC $40  ; [A] = [A] + [0040] + C
```


Yukarıdaki programda ilk satırda CLC bir önceki programdan kalan ve şu anki programa etki edebilecek eldelerden kurtulmak için C bayrağını temizlenir. Daha sonra A'ya 25H verisi yüklenir. Bir altındaki adımda A'daki veri [0040] no' lu bellek konumundaki veri ve elde toplanarak sonuç yine A'ya yazılıyor.

#### Çıkarma işlemi
Tekrar hatırlatacak olursak değişik mimari türlerinde değişik komutlar kullanılmaktadır, bunlar karıştırılmamalıdır. SUB, SUBI, SUBU, SBC değişik mimarilerdeki çıkarma komutlara örnektir. Mesela 6502'de SBC çıkarma komutu ile, A'daki değerden bellek konumunun değeri ve eldeki değer çıkarılır. Sonuç yine biriktiricide kalır. Borç, elde bayrağının(C bayrağı) ters dönmüş hali olarak düşünülebilir. Bu işlemi sembolik olarak şu şekilde gösteririz

A = A - M - C

Çıkarma işlemi, toplama işlemindeki gibi hem ikili sayılarla hem de BCD modunda yapılabilir. Burada c = (1 - C) ifadesi çok baytlı çıkarma işlemlerinde kullanılır. C = 0 ise sonuca etki edilmez. Çünkü C = 1 ise, tersi 0 olur.

### Boolean mantık komutları
Boolean mantık komutları Boolean aritmetik işlemlerinde olduğu gibi aynen uygulanır. AND, NOT, OR ve XOR işlemlerini uygulamak için komutlar bulunur.
 
Bu komutlar, biriktiricideki değerle bellek konumundaki değeri bit bit mantık işlemine sokarlar ve daha sonra sonuç biriktiriciye yazılır. Bütün bu işlemler N (Negatif) ve Z (Sıfır) bayraklarını etkiler. Bu komutlardan en yaygın kullanılanları AND ve OR komutlarıdır.
 
AND komutu başka bitlere etki etmeden istenen bitin maskelenmesinde de kullanılır. Programcı bellek konumundaki temizlemek istadiği veriye göre A'ya değer atmalıdır.
 
OR komutları AND'in tersine istenen belirli bitleri 1 yapmada kullanılır.

### Bit işleme komutları
Bit işleme komutları, verilen bir veri sözcüğün içindeki bitleri veya bit gruplarını 1(set) veya 0(reset) yapmada kullanılır. Bunlar sola veya sağa aritmetik ve mantıksal kaydırma ve döndürme komutlarını içerir. Mantıksal kaydırma komutları, bitleri belirtilen miktarda sola ya da sağa kaydırırmada kullanılır (left shift and right shift). 
 
Genellikle ikiyle çarpma ya da bölme işlemleri için kullanılan aritmetik kaydırma komutları en soldaki bit sayının işaretini gösterdiğinden bu biti kaydırma. Sağa doğru yapılan aritmetik kaydırmada, işaret biti yanındaki bite kopyalanır. Sola doğru yapılan aritmetik kaydırmada bitler sola kaydırılır, sağdan sıfırlar içeriye girerler, ancak işaret biti sabit kalır, hareket ettirilmez. Döndürme komutları kaydırılmış bitlere kaydırma yapan komutlardır. Mesela sola 1 bit döndürmede en soldaki bit dışarı kaydırılır ve en sağdaki bit haline getirmek için de döndürme yapılır.

### Giriş/çıkış komutları
Giriş/Çıkış komutları, mimariden mimariye pek çok değişiklik gösterir. G/Ç'ı kontrol etmek için bazı temel düzenler kullanılır. Bunlar programlanmış G/Ç, kesinti sürümlü (interrupt-driven) G/Ç ve DMA aygıtlarıdır.

### Denetim aktarım komutları
Kontrol komutları dallanmalardan, atlamalardan ve yordam çağırmalarından oluşur. Dallanmalar koşullu ya da koşulsuz olabilir. Atlama komutları dallanma komutlarına benzer. Dallanma komutlarının adres içeren bir şeklidir. Atlama komutları farklı durumları belirtmek için genellikle bellek adres konumunun bitlerini kullanır, çünkü işlenene ihtiyaç duymaz. Yordam çağırmaları dönüş adresini otomatik olarak saklayan özel dallanma komutlarıdır. Geri dönüş adresini kaydetmek için farklı makineler farklı uygulamalar kullanır. Bazı makineler adresi bellekte belirli bir yere kaydeder, bazıları bir yazmaca kaydeder, bazıları da adresi yığına bir veri gibi kaydeder. Genellikle en çok kullanılan yöntem de yığına atmaktır (PUSH ve PULL komutlarıyla atılır ve alınır).

#### Şartsız dallanma komutu
Şartsız herhangi bir adrese gitme işlemini JUMP komutu gerçekleştirir. Eğer bu komutunun devamındaki komut veya komutlar işlenmeyecekse bu komut kullanılır. JUMP komutu, mutlak adresleme veya dolaylı adresleme modlarından birisini kullanır.
#### Şartlı dallanma komutu
Şartlı dallanmada gerekli şart sağlandığı anda program belirlenen hedefe sapar. Şartlı dallanma komutlarını, dalma komutundan ayırt edebilmek için sapma adını aldı. Eğer şart sağlanmazsa program bir sonraki komuttan işlemeye devam eder. Şartlı dallanma komutları aşağıdaki sıra ile çalışır:
* CPU işlem kodunu alıp getirir ve durumun ne olduğunu kontrol eder.
* CPU öne sürülen şarta bakar. Bu şartlar şunlardır:
** sonuç negatif mi?
** sonuç sıfıra eşit mi?
** elde (C) bayrağı 1&nbsp;mi?
* Eğer koşulan şart sağlanırsa, program sayıcının içeriği o anki adresle yüklenir.
* Eğer koşulan şartla sağlanmazsa, CPU sıradaki komutu işler.

JUMP komutu kontrolü bellekte belirli bir adrese aktarır, sapma komutları kontrolü, komut işlendikten sonra bir sonraki komutun bulunduğu yerden ilerideki veya gerideki belirli bir bellek konumuna aktarır. Dalma komutu ile sapma komutu arasındaki diğer bir fark ise, sapma komutları karar verme komutlarıdır. Sapma şartları mikroişlemci durum bayraklarından C (elde), N (negatif veya işaret), Z (sıfır) ve V (aritmetik taşma) bayraklarına göre gerçekleşir.
### Özel amaçlı yazmaçlar
Özel amaçlı komutlar arasında dizi işleme, yüksek seviye dil desteği, koruma, bayrak kontrolü ve önbellek yönetimi de vardır. Birçok mimari dizi işlemek için özel komutlara sahiptir. Bu özel komutlar için mimarilerde özel yazmaçlar bulunabilir.

## Komutların geçtiği temel aşamalar
Komutlar işlenirken geçtiği belirli aşamalar vardır. Bunlar:

# programın komutlarını alıp getirme (*fetch*)
# çözme (*decode*)
# işletme (*execution*)
# sonucun saklanması
# bir sonraki komutun yakalanması.

Bir programı işletmek için, işlemci birim zamanda bir komut getirir ve belirtilen işlemi uygular. Komutlar, bir dallanma veya bir atlama komutuna rastlayana kadar ardışık bellek konumlarından getirilir. İşlemci, program sayacını (Program Counter, PC) kullanarak, getirilecek bir sonraki komutu içeren bellek konumunun adresini saklar. Komut getirildikten sonra, program sayacının içeriği dizideki bir sonraki komutu gösterecek şekilde güncellenir. Bir dallanma komutu program sayacına farklı bir değer yükleyebilir.

İşlemcideki bir başka kilit yazmaç ise komut yazmacıdır (Instruction Register - IR). Her bir komutun 4 bayttan(1 sözcük) meydana geldiğini ve tek bellek sözcüğünde depolandığını varsayalım. Bir komutu işletebilmek için, işlemci aşağıda belirtilen adımları sırasıyla izler:
 
* Program sayacı tarafından gösterilen bellek konumunun içeriği getirilir. Bu bellek konumunun içeriği işletilecek bir komut olarak yorumlanır. Bu nedenle bu içerik komut yazmacına yüklenir. Bu durum sembolik olarak aşağıdaki gibi ifade edilir: 
IR ← PC

* Belleğin bayt adreslenebilir olduğunu varsayarak, PC'nin içeriği 4 arttırılır.
PC ← [PC] + 4

* Komut yazmacındaki komut tarafından belirtilen faaliyetler yerine getirilir.

Eğer bir komut bir sözcükten fazla yer kaplıyorsa 1. ve 2. adımlar tüm komut getirilene kadar tekrarlanmalıdır. Bu iki adım genellikle getirme evresi, 3. adım ise işletme evresi olarak adlandırılır.

Bazı istisnai durumlarda, bir komutun aşağıdaki işlemleri belirli bir düzende 1 ya da daha fazla sayıda uygulaması gerekir:

* Bir işlemci yazmacından diğer bir yazmaca ya da AMB'ye 1 sözcük büyüklüğünde veri aktar. 
* Bir aritmetik veya mantık işlemi uygula ve işlemin sonucunu işlemci yazmacına yaz. 
* Verilen bir bellek konumunun içeriğini getir ve işlemci yazmacına yaz. 
* Bir işlemci yazmacındaki 1 sözcük büyüklüğündeki veriyi verilen bir bellek konumuna yaz.
İşlemcilerin organizasyonu, son yıllarda teknolojide yaşanan gelişmeler ve diğer taraftan başarıma olan ihtiyaçtan dolayı oldukça gelişti. Yüksek başarımlı işlemcilerin geliştirilmesindeki yaygın bir yönteme göre çeşitli fonksiyonları yerine getiren birimler mümkün olduğunca paralel bir şekilde çalışmalıdır (Boru hattında olduğu gibi). Yüksek başarımlı işlemciler ardışık (pipelined) bir organizasyona ve yapıya sahiptir. Bir komutun işletilmesine önceki komutun işletilmesi bitmeden önce başlanır ve bir süre sonra her bir saat vuruşunda mükemmel bellek varsa bir komut içeriye alınır ve bir komutun işletilmesi sonuçlandırılır. Süper skalar işletim adı verilen bir başka yaklaşımda aynı anda birçok sayıda komut getirilip işletilir.

## ISA örnekleri

### Intel
Intel sağdan anlamlılığı ve iki adresli mimariyi değişik uzunluktaki komutlarla kullanan bir mimaridir. Intel işlemcileri, bütün komutların bir bellek mahalinde işlem görebilme anlamına gelen yazmaç-bellek mimarisini kullanır, fakat diğer işlenen bir yazmaç olmalı. Bu ISA mimarisi değişik uzunluktaki komutların veri üzerinde işlem görmesine izin verir, örneğin 1, 2 veya 4 bayt uzunluğundaki komutlar.

### MIPS
MIPS sağdan anlamlılığı kullanan, bayt adreslenebilir, üç adresli, sabit komut ve hafıza uzunluklu bir mimaridir. Sadece load ve store komutlarının belleğe ulaşabildiği yükle ve sakla mimarisidir. Diğer bütün komutlar işlenenler için yazmaç kullanmak zorundadırlar. Bu çok geniş bir yazmaç kullanımını gerektirir. MIPS aynı zamanda sabit uzunluklu işlemler kullanır.

### Java Virtual Machine
Java platformdan bağımsız olması açısından son derece ilginç ve son zamanlarda popülerliği artan bir dildir. Kod bir mimari üzerinde bir kod derlenmişse ve program farklı bir mimaride çalıştırılmak isteniyorsa bu, kod değiştirilmeden veya yeniden derlemeden yapılabilir.

Java derleyicisi program ilk çalıştırıldığında yazmaç sayısı, bellek boyutu, I/O girişleri gibi mimari bağlanımları açısından bir kısıtlama getirmez. Fakat daha sonra programı çalıştırmak için bir Java Virtual Machine (JVM)'e ihtiyaç duyulur. JVM asıl olarak donanım mimarisine giden bir katlayıcı fonksiyonu görür ve platforma bağımlıdır. Fakat JVM belli bir mimari üzerinde görüldüğü zaman herhangi bir ISA'de derlenmiş bir programı çalıştırabilir. Çalıştırma anında JVM'in görevi baytkodları yükleme, kontrol etme, bulma ve yürütmedir. JVM sanal olmasına rağmen iyi tasarlanmış bir komut kümesi mimarisidir.

Komut kümesi mimarileri değişik tasarım ilkelerini kullanır. Komut kümesi mimarisinde başlıca hedefler; daha güçlü işlemler sunmak, komut sayısını ve karmaşıklığını azaltmak, hızı artırmaktır. Buna karşılık daha yavaş saat sıklığı ve yüksek komut başına çevrim (cycles per instruction) ise karşılaşılabilecek risklerdir. Komut kümesi mimarisi için iyi bir soyutlama gerekir.

## Kaynakça

## Dış bağlantılar
* A64 Instruction Set Architecture Guide
* RISC-V Instruction Set Manual