Makine
İşlemci nasıl çalışır: mantık kapılarından yukarıya
İşlemci sihir değil; prensipte karmaşık bile değil. Bir sayı listesini gösteren bir sayaç, her sayıyı anahtar ayarlarına çeviren bir kod çözücü ve birkaç arkadaşıyla bir toplayıcı. Bu sayfa parçaları bir araya getiriyor ve makinenin tek bir vuruşunu adım adım izliyor.
Parça listesi
1971’deki Intel 4004’ten telefonundaki çipe kadar neredeyse her işlemci aynı birkaç bloktan oluşur:
- Bellek, programı ve verisini numaralı sözcükler hâlinde tutar. (Bazı tasarımlar ikisini ayrı belleklerde tutar; buna aşağıda değineceğiz.)
- Program sayacı (PC), bir sonraki komutun adresini tutan bir yazmaçtır. Normalde her adımda bir komut ileri sayar.
- Komut yazmacı ve kod çözücü, o anki komutu tutar ve bitlerini kontrol sinyallerine çevirir: hangi yazmaç okunacak, ALU ne yapacak, belleğe yazılacak mı.
- Yazmaçlar, o anda üzerinde çalışılan değerler için birkaç hızlı saklama yuvasıdır. Flip-floplardan kurulurlar.
- ALU (aritmetik mantık birimi), toplama, çıkarma, karşılaştırma, VE, VEYA ve kaydırma yapan kombinasyonel bir mantık bloğudur. Hangi işlemi yapacağını birkaç kontrol biti seçer. Çekirdeğinde bir toplayıcı vardır.
- Bayraklar, son sonuçla ilgili sıfır, negatif, elde ve taşma gibi bilgileri kaydeden tek bitlerdir; sonraki komutlar bunlara göre dallanabilir.
Komut çevrimi: getir, çöz, yürüt
Bir işlemci, açık olduğu sürece üç adımı tekrarlar:
- Getir (fetch). PC’nin gösterdiği adresteki sözcüğü komut yazmacına oku ve PC’yi bir sonraki komuta ilerlet.
- Çöz (decode). Komutu alanlarına ayır. Genellikle bir işlem kodu (opcode) ne yapılacağını, işlenen alanları da neyle yapılacağını söyler. Kod çözücü bu bitleri kontrol sinyallerine çevirir.
- Yürüt (execute). Kontrol sinyalleri veri yolunu ayarlar. Değerler yazmaçlardan ya da bellekten ALU’ya akar ve sonuç geri yazılır. Bir atlama komutu işini PC’ye yeni bir değer yükleyerek yapar; böylece bir sonraki getirme başka bir yerden olur.
Hepsi bu kadar. Döngüler, fonksiyon çağrıları, işletim sistemleri ve oyunlar; hepsi bu çevrimin saniyede milyarlarca kez tekrarlanmasıyla kurulur. Küçük bir örnek düşün: tek bir yazmacı (akümülatör), 16 baytlık belleği ve 4 bitlik işlem kodu ile 4 bitlik adresten oluşan sekiz komutu olan oyuncak bir bilgisayar. Böyle bir makine 5 + 4 + 3 + 2 + 1’i bir döngüyle toplayabilir; her komut için getir, çöz ve yürüt adımlarını sırayla atarak.
Programlar da sadece sayı
Bu oyuncak makinede ADD 15 komutu 0010 1111 baytı olarak saklanır: işlem kodu 2, adres 15. Bellek bir sözcüğün komut mu sayı mı olduğunu bilmez; önemli olan işlemcinin onu nasıl kullandığıdır. Bu, ilk kez 1948’de Manchester Baby üzerinde çalıştırılan depolanmış program (stored-program) fikridir. Bilgisayarları genel amaçlı yapan da budur: makinenin ne yaptığını değiştirmek için kabloları değil, bellekteki sayıları değiştirirsin.
O sayıları elle yazmak çabucak bıktırır, bu yüzden programcılar assembly dili (ADD 15) yazar ve assembler (çevirici) denen bir program bunu makine koduna çevirir. Hangi komutların var olduğu ve nasıl kodlandığı, makinenin komut kümesi mimarisidir (ISA): donanımla yazılım arasındaki sözleşme. Bkz. kendi komut kümeni tasarlamak.
Tek çevrimli, çok çevrimli, boru hatlı
Yukarıdaki oyuncak makine her aşamaya ayrı bir adım ayırır; buna çok çevrimli (multi-cycle) tasarım denir. Tek çevrimli (single-cycle) bir işlemci üç aşamanın hepsini tek ve uzun bir saat vuruşunda yapar; basittir ama yavaştır, çünkü saat periyodu en yavaş komutu kapsamak zorundadır. Gerçek işlemciler boru hattı (pipeline) kullanır: bir komut yürütülürken bir sonraki çözülür, ondan sonraki de getirilir; tıpkı bir montaj hattı gibi. Boru hattının kendi bulmacaları var, bunlara tehlike (hazard) denir. Bir komut henüz yazılmamış bir sonuca ihtiyaç duyarsa ne olacak? Sonucu henüz belli olmayan bir dallanmadan sonra ne getirilmeli? Cevaplar yönlendirme (forwarding), bekletme (stall) ve dallanma tahmini. Modern işlemciler sıra dışı yürütme (out-of-order execution) ve yan yana çalışan birden çok boru hattıyla daha da ileri gider.
Von Neumann ve Harvard
Von Neumann makinesi komutları ve veriyi tek bir bellekte tutar ve ona tek bir yoldan ulaşır. Esnektir, bir program başka bir programı bile yükleyebilir; ama komut getirme ile veri erişimi bu tek yol için yarışır. Harvard makinesinin ayrı komut ve veri bellekleri vardır, bu yüzden ikisini aynı anda yapabilir. Birçok mikrodenetleyici Harvard makinesidir. Büyük işlemcilerin çoğu ana bellek düzeyinde von Neumann’dır ama çekirdeğe yakın yerde komut ve veri önbelleklerini ayırır; böylece ikisinin de avantajlarından biraz alır.
Bir işlemci kaç kapıdan oluşur?
Basit bir işlemci için düşündüğünden az. Küçük bir 8 bitlik işlemci birkaç bin NAND eşdeğeriyle kurulabilir; Apple II’ye güç veren 6502’de yaklaşık 3.500 transistör vardı. Modern bir masaüstü işlemcide on milyarlarca transistör var. Fikirler aynı; sadece tekrarlanmış, genişletilmiş ve hızlandırılmış: daha büyük ve daha çok yazmaç, önbellekler, çok sayıda boru hattı ve çekirdek.