Dijital Simulasyon ve İşlemci Tasarımı

Transkript

Dijital Simulasyon ve İşlemci Tasarımı
Dijital Simulasyon
ve
İşlemci Tasarımı
David Currie, ST John's Collage
Mühendislik ve
Bilgisayar Bilimleri, Bölüm 2, 1998
Supervisor - Dr J Sanders
1
İçerik
1
Giriş ........................................................ 3
2
Programlama Dilleri ............................... 5
3
Simulasyon ............................................. 5
4
Düzenleyici ve Simulator ........................ 8
5
Temel Bileşenler ..................................... 10
6
Sadeleştirilmiş MIPS Komut Seti ........... 18
7
Tek Döngülü İşlemci ............................... 19
8
Çift Döngülü İşlemci .............................. 27
9
İş Hatlı (Pipelined) İşlemci ....................... 33
10
Sonuç ...................................................... 37
11
Referanslar .............................................. 38
Ek-A - İlerleme Raporu .......................... 38
2
1. Giriş
1.1 Arka Plan
1960'ların ortalarında entegre devrelerin keşfi ve 3. nesil bilgisayarların üretilmesiyle
üreticiler daha küçük silikon parçaları üstüne daha çok transistor sığdırmak için yollar arıyorlardı.
Tasarımcılar bu artan bilgisayar gücünü, COBOL ve Pascal gibi yüksek seviye dillerle düşük seviye
assembly dili arasındaki anlamsal boşluğu doldurma amacıyla daha da karmaşık komut setleri
oluşturmak için kullandılar.
Bu sözde karmaşık komut setli bilgisayarlar (CISC – Complex Instruction Set Computers),
işlemciye oranla çok yavaş olan ana bellekle kıyaslandığında heyecan vericiydi. Bu yapıda, örneğin
ikilik sistemden onluk sisteme çeviri gibi genel bir fonksiyonun, yavaş kütüphane rutinlerinden
çağrılması yerine basitçe yeni bir komut ekleniyordu.
1970'lerde işler değişmeye başladı. Öncelikle yarı-iletken RAM bellekleri artık ROM'lardan
10 kat daha yavaş değildi. Ayrıca bu karmaşık mikrokodları yazmak, debug etmek ve bakım
yapmak giderek zorlaşan bir iş oluyordu - mikrokodda bir bug bütün yüklenmiş ROM'ların
değişmesi anlamını taşıyor. Üçüncü olarak Tanenbaum gibi akademisyenler programların genel
yapısını incelediler ve kullanılan komutların ortalama %80'inden fazlasının basit işlemlerden
oluştuğunu keşfettiler, if koşulları, prosedür çağırmaları gibi. Görevlerde %95 oranında sağ tarafta
ya sadece tek bir operatör bulunuyor ya da hiç bulunmuyordu. Bütün çağırmaların %90'ından
fazlasında 5 değişkenden daha azı kullanılıyor ve prosedürlerin %80'inde 4 yerel değişkenden azı
bulunuyordu. Bu sonuçların özeti insanların karmaşık kodları yazmıyor olmasıydı.
Daha çok komut daha fazla adresleme noktası demektir ki bu da daha büyük ve yavaş bir
yorumlayıcı anlamına gelir. Mikroprogramlama artık bilgisayarların verimliliğini düşüren bir hal
almıştı. Bu durum yeni nesil RISC (Reduced Instruction Set Computers – İndirgenmiş Komut Setli
Bilgisayar) işlemcilerin, IBM 801 (1975), the Berkley RISC1 (Patterson ve Sequin 1980) ve
Stanford MIPS (Hennessy, 1984) habercisi oldu. Hepsinin ortak amacı veriyolundaki işlem süresini
azaltmaktı. Tablo 1'de RISC işlemcilerin karakteristik özellikleri sunulmaktadır.
Tek döngü süren basit komutlar
Sadece referans belleğe yukleme/kaydetme
Yüksek seviye iş hattı (pipeline)
Komutların donanım tarafından işlenmesi
Sabit komut formatı
Az sayıda komut ve mod
Karmaşık yapının derleyici üzerine kaydırılması
Çoklu yazmaç setleri
Tablo 1 – RISC işlemcilerin karakteristik özellikleri
3
1.2 Projeye Genel Bakış
Bu projenin amacı, işlemci ünitesini tasarlamak, oluşturmak ve dijital simulasyon ortamında
test etmektir. Bu RISC ve CISC mimarileri arasındaki temel farkları karşılaştırmak ve ortaya
koymak için kullanılacaktır. Devreler Şekil 1'de görülen en düşük 3 seviyeyi, yani dijital mantıktan
geleneksel makine seviyesine test için hazırlandı. Bu yaklaşımın amacı kritik parçaların farklı
tasarımlardaki ayrıntılı analizi ile her elemanda meydana gelen gecikmeleri görebilmektir.
Şekil 1 – Modern Bilgisayarın Katmanları
1.3 Hedefler
Projenin hedefleri aşağıda verilmiştir:
1. Dijital simulator ve grafiksel arayüzü tasarımı ve yapımı
2. CISC işlemci tasarımı ve simulasyonu
3. RISC işlemci tasarımı ve simulasyonu
4. Simulator kullanarak bu iki işlemcinin performanslarını kıyaslanması
Daha ileri arkaplan çalışmaları RISC ve CISC işlemcileri arasındaki farkların o kadar da
kesin ve belirgin olmadığını gösterdi. Pipelining örneğin sadece RISC'lere özgü bir yapı değildir.
Aynı şekilde RISC işlemcilerde kontrol birimi karmaşıklığının gerekli kıldığı durumlarda
mikroprogramlama kullanılabilir. Aynı şekilde, her ne kadar RISC komutları sabit uzunlukta olsada
genellikle üç ya da daha fazla farklı format kullanılır. Hedefleri değiştirmemdeki son nedenimse,
devreyi, özellike karmaşık komut setini kullanırken olabildiğince basit tutmak istememdi.
Bu sebeplerle MIPS işlemcilerde kullanilan tek bir komut setinin baz alınmasına karar
verildi. Bu RISC işlemciler için ana hedef olan veriyolu işlem süresini kısaltmak da dahil birçok
şekilde kullanılabilir.
4
2. Programlama Dili
İlk ve önemli kararlardan biri programın hangi platform için yazılacağına ve hangi dille
yazılacağına karar vermek. Her ne kadar PC/Windows tercih edilen geliştirme ortamı olsa da Sun /
Solaris de bilgisayar labaratuarında kullanım için uygun bir seçenekti.
Giriş değerlerinin verilmesi ve simulasyonun izlenmesi için, seçilecek dilin karmaşık
grafiksel kullanıcı arayüzünü (GUI – Graphical User Interface) desteklemesi gerekiyor. TCL / TK,
Xlib, Xview ve Motif gibi paket programlar, X Windows altında çalışırken bu işi kolaylaştırabilir.
Bu ne yazik ki Sun / Solaris platformunu kullanımımızı kısıtlar. Benzer şekilde Visual C++ ya da
benzer bir geliştirme platformu kullanımı da programın sadece Windows'ta çalışabilmesini sağlar.
Nesne yönelimli bir programlama dili mantıklı bir seçim. Projenin temeli olan mantık
kapıları nesne uygulamasıyla kolayca uyum sağlayacak yapıda. Nesne metotları (fonksiyonları),
giriş, çıkış sinyalleri ve devrenin olabileceği state durumlarına karşılık gelir.
Projeyi Java ile hazırlama kararı verildi. Java'nın platform bağımsızlığı sayesinde Solaris ve
Windows da dahil olmak üzre desteklenen herhangi bir platformda proje geliştirilebilir ve
kullanılabilir. Java nesne yönelimli bir dil ve her ne kadar bana yeni olsada cok iyi olduğum C++'a
yakınlığı işi kolaylaştırıyor. Java AWT sınıfı pencere, menü vb grafiksel kullanıcı arayüzü (GUI)
elemanlarını kolayca yapmamıza olanak sağlıyor. Version 1.1 çok kullanışlı olan yeni 'event' tabanlı
modellemeyi sağlıyor. Takma adı Swing olan Java Foundation Class (JFC) (her ne kadar tam
sürümü projenin sonuna doğru geliştirilmesine rağmen) da projede kullanıldı. Bu sınıf toolbar,
popup menüleri ve çok yardımcı olan çift tamponlu scroll panelleri kullanmamıza olanak sağlıyor.
Swing sınıfı 1.2 sürümünden itibaren Java'da standart olarak eklenmiş durumda.
3. Simulasyon
3.1 Uygulanabilecek Stratejiler
Simulatör tasarlamadan önce kullanılacak stratejinin belirlenmesi gerekiyor. Üç olası
seçenek mevcut ve bunlar aşağıda ele alınıyor.
3.1.1 Asenkron Simulasyon
İlk akla gelen bu strateji en kolay olan seçenek. Mantık kapısının giriş değerini
değiştirdiğimizde çıkış değeri de değişir. Ne yazık ki bu fazla basitleştirmiş bir anlatım. Her ne
kadar proje sequential (ardışık) devre simulasyonu için olsada sinyaller yine de paralel ilerliyor.
Şekil 2'deki çkış değerleri hep 0 olan basit devreye göz atalım. Başlangıç değerinin 0
olduğunu varsayalım. Şimdi de girişi 1 yapalım. Önce üstteki girişi mi 1 yaptık yoksa alttakini mi?
Eğer önce alttakini 1 yaparsak çıkış 0 olarak kalmaya devam eder, ama eğer önce üsttekini 1
yaparsak çıkış, alttakini 1 yapana kadar geçici olarak 1 olacaktır.
Şekil 2 – Paralel Sinyaller
Peki ya Şekil3'teki devre? Geri besleme bağlanmadan önce üstteki giriş 1 ve alttaki 0 olsaydı
5
çıkış 1 olacaktı. Geri beslemenin bağlanması, üstteki girişi 1 yapacak. Bu durum çıkışı 1 yapacak ki
bu da üst girişi 1 yapacak. Bu sonsuz döngü sadece girişler değiştiğinde çıkışı değiştirerek
önlenebilirdi, ancak bu programı daha karmaşıklaştıracaktır.
Şekil 3 - Salınım
Şimdi Şekil 3'ü başlangıç değerleri olarak girişleri 1 çıkışı 0 olarak ele alalım. Geri besleme
bağlandığında üst girişi 0 yapacak. Bu çıkışı 1 yapacak, üst giriş 1 olacak. Bu sefer sonsuz salınımı
simule ederken devrenin geri kalanının işlemini bozmamak için daha da çok dikkat etmemiz
gerekecektir.
3.1.2 Senkronize Simulasyon
Senkronize simulasyon stratejisi devrede var olabilecek herhangi birşeyden son derece ayrı
olarak var olan bir clock sinyaline dayanır. Clock üç fazlıdır. İlk fazda bütün mantık kapıları
girişlerindeki değerleri okurlar, ikinci fazda yeni çıkış değerlerini hesaplarlar ve üçüncü fazda da
çıkışlarına hesaplanan değeri yansıtırlar. Bu ayırma sayesinde bir sonraki clock sinyaline kadar giriş
değerleri etkilenmeyeceği için sinyaller çıkış fazı sırasında istendilen şekilde paralel olarak
sorunsuzca gönderilebilirler.
Şekil 3'teki salınım clock oranına bağlı olarak oluşacak. Şema kapılarda oluşacak
gecikmeleri gösteriyor. Örneğin, Şekil 4'te giriş 0'dan 1'e dönüştüğüde sadece bir clock döngüsü
sonra sonuç çıkışta görülecektir.
Şekil 4 – Mantık kapısında oluşan gecikme
3.1.3 Yarı Senkron
Bu strateji farklı uzunluklarda clock sinyallerinin mümkün olduğu bir senkronize strateji
üstüne kuruluyor. Eğer tek bir clock sinyalinin süresi bütün kapıların yeniden değerlendirilmesi için
gereken süreden azsa bu durum devreye giriyor. Bu kapıların bazılarının çıkış değerlerini yazmadan
önce diğerlerinin giriş değerlerini okuması durumunu engelleyebiliyor.
6
3.2 Gerçekleme / Uygulama
Yarı senkron strateji kullanımına karar verildi. Elektronik paketleri temsilen soyut (abstrakt)
bir Java sınıf paketi oluşturuldu. Paketin construct metodunda sırasıyla giriş ve çıkışları
değerlendirmesi üzre addinput() ve addoutput() metotları kullanıldı. Initialize() ve simulate()
metodları paket genişletilirken tanımlanmalı. Resetlenme durumunda cağrılan former initialise state
olarak kullanılabilir. Latter girişlerin okunup çıkışların oluşturulduğu her clock sinyali arasında
cağrılır. Bu iki metot isimlerinde de anlaşılacağı üzre giriş değerlerini almak ve çıkış değerini
atamak üzre getinput() ve setoutput() metotlarını kullanabilir.
Aşağıdaki örnek bir nand kapısının tasarımında bu yaklaşımın ne kadar kolay olduğunu
gösteriyor. Construct() metodunda a ve b girişleri ile c çıkışı pakete ekleniyor. Ayni şekilde bit
genişliğini belirten bir sayı da isimlerle birlikte kullanılıyor. Nand kapısının state'i olmadığı için
initialise metodu boş. Simulate() metodu iki giriş değerini alıyor ve çıkış değerini üretiyor. Burada
getinput() ve setoutput() metodları boolean değerleri gereken bit dizinini belirtiyor. Eğer gerekirse
bu metodlar dizin olmaksızın, bütün girişlerin geri döndürülmesi (return) ya da çıkışın binary bir
nesne kullanarak belirlenmesi şeklinde kullanılabilir. Binary sınıfı simulasyon sınıfını daha kolay
yazmak için toplama, çıkarma, tersini alma gibi binary işlemleri yapan metotlara sahiptir.
class NANDGate extends Package {
public void construct () {
addInput("a", 1);
addInput("b", 1);
addOutput("c", 1);
}
public void initialise() {
}
public void simulate() {
setOutput("c", 0, !(getInput("a", 0) && getInput("b", 0)));
}
}
Paket sınıfı kullanıcıyı simulasyon stratejisinin karmaşasından korur. Simulasyon
başlatıldığında clock sinyali üreten bağımsız bir thread de başlamış olur. Her clock sinyalinin
başında simulasyonda bulunan bütün paketlerin readinputs() metotlari cağrılır. Bu metot paket
içinde bulunan bütün giriş verilerini mevcut clock döngüsü sırasında oluşabilecek değişimlerden
korumak üzre kaydeder. Getinput() çağrıları kaydedilen verileri geri döndürür. Clock sonrasında
bütün bileşenlerdeki simulate metotlarını cağırır. Setoutput() metodunun çağrılması basitçe
paketteki yeni çıkışların kaydedilmesidir. Sadece writeoutputs() metodu çağrıldığında değerler çıkış
bağlantılarına gönderilir. Bu şekilde yapılmasının nedeni ileride daha iyi anlaşılacak.
Bir çıkışın değeri 1 yapıldığında bu çıkışa bağlı bütün bağlantıların hepsi 1 yapılır.
Sonrasında bu bağlantıların diğer uçlarında herhangi bir bileşenin girişi olup olmadığı kontrol edilir
ve eğer varsa o değerlerde 1 yapılır. Her ne kadar bir çıkış bağlantısından birden fazla bağlantı
(wire) çıkabiliyorsa da boolean değerlerindeki karmaşayı önlemek için girişlerde bir bit için sadece
tek bir bağlantı olabilir.
Java'da kullanılan mantık anahtar ifadeleri 'true' ve 'false' ikilik sistemdeki 1 ve 0'i temsil
eder. Simulasyonda floating düşük/yüksek seviyeler tanımlanmayarak, sadelik tercih edilmistir.
Bütün giriş ve çıkışlar aksi bir durum olmadıkça 0'dır.
7
4. Düzenleyici (Editor) ve Simulatör
Bu bölüm düzenleme ve simulasyon paketlerinin kullanımı ve işleyişiyle ilgili özet bilgiler
sunuyor.
Baslangıç olarak kullanıcıya Şekil 5'te gösterilen siyah noktalı bir ekran sunulur. Buraya
kullanıcı giriş, çıkış ya da paket ekleyebilir. Paketler derlenmiş ve diske kaydedilmiş Java sınıf
dosyalarından seçilebilir. İlk olarak nand kapısı, clock, 1 düzey kaynağı ve 0 düzey kaynağı sınıf
dosyaları yazılmıştır.
Şekil 5 – Başlangıçtaki ekran görüntüsü
Daha sonra paket bağlantıları wire kullanarak yapılabilir. Bağlantılar tek bitten daha geniş
olabileceği için kullanıcının wire ile hangi bitleri bağladığını belirtmesi gerekir. Bir giriş bağlantısı
sırasında üstüste binmelerin engellenmesi için eş zamanlı olarak gerekli kontroller yapılır. Paketler
ve bağlantılar sürüklenerek ya da bir pop up menü ile silinerek yeniden konumlandırılabilir. Fare
imlecinin paket veya bağlantı üstünde bir süre tutulması, Şekil 6'da da görüldüğü üzre bileşen adını
içeren bir yazı kutusunun getirilmesini sağlar.
Açıklığa destek olmak için paketler üstüste binemez. Bağlantılar kesişme noktalarında
karışıklığa sebebiyet verilmemesi için paketlerden başlayarak eklenebilirler. Bu yüzden bağlantılar,
aynı sinyali taşıdıkları sürece birbirleriyle kesişebilirler.
Eğer devrenin kendisi tekbir paketse kendine ait giriş ve çıkışlar eklenebilir ya da
isimlendirilebilir. Devre sonuçları bir simulasyon dosyasına kaydedilip daha sonra başka bir
devreye “Add Package” şeceneği ile eklenebilir. Bu yapı tasarıma modüler bir yaklaşım olanağı
sunar. Şekil 6'da clock.class paketiyle notgate.sim paketinin nasıl birbirlerine bağlandıkları
görülüyor. Bu devre kaydedildiğinde eklenmiş paketlerdeki tanimları kaydetmez. Bunun yerine
sınıfın adı ya da simulasyon dosyasının adresi kaydedilir. Bunun anlamı paketlerin iç yapısında
yapılabilecek değişikliklerle oluşturulacak yeni versiyonların, devre yüklendiğinde kendiliğinden
değistirilmiş olarak geleceğidir. Tabiyki giriş ve çıkış bağlantıları değiştirilmemesi gerekiyor.
8
Şekil 6 – NOT kapısına bağlanmış clock
Pencerenin üstünde yer alan tuşlar simulasyon menüsündekilerin aynısıdır. Bunlar
simulasyonun adımlanması, calışması, durması ya da resetlenmesini kontrol ederler. Simulasyonu
icra eden threadin önceliği, bu tuşlarla kontrol edilip mevcut durumda kesmeye uğratılabilsin
(interrupt) diye düşük tutulmuştur. Simulasyon sırasında bağlantı ve kablolar herhangi bir bitleri 1
olduğunda yeşil aksi takdirde kırmızı görünürler. Bu özellikle işlemci devrelerinin kontrol birimini
izlerken cok fayda sağlayan bir özellik.
Diğer üç metot kullanıcıya simulasyonu daha ayrıntılı izleme imkanı sunar. Bağlantı
noktasına eklenecek probe sayesinde gerçek zamanlı olarak giriş-çıkış verilerini izleyebileceğimiz
bir pencere açılır. Şekil 7, Şekil 6'daki NOT kapısının giriş ve çıkışına bağlanmış probe sinyallerini
gösteriyor. Çizgilerin üstüne yaklaştırma yapılabilir. Burada da kapı gecikmesi net şekilde
görülebiliyor (not: zaman sağdan sola doğru artıyor). Çoklu-bit bağlantılarda ikili değerleri gösteren
monitörlü bağlantılar daha kullanışlıdır.
Şekil 7 – Şekil 6'daki devrenin probe göstergesi
Üçüncü metot paketlerin statelerini incelemeye olanak sağlar. Yansıma (reflection) isimli bir
Java tekniği kullanarak program, bir sınıfın herhangi bir niteliğinin public olarak tanımlanıp
tanımlanmadığını kontrol eder. Eğer public ise niteliğin adı ve mevcut değeri gösterilir. Bu durum
özellikle simule edilen hafıza biriminin içeriğini görüntülerken yarar sağlamıştır.
9
5. Temel Bileşenler
Bu bölüm işlemci için gerekli olan kombinasyonal mantığın nasıl NAND gibi tamamen
mantık kapılarından oluşturulduğunu inceliyor.
5.1 NAND Kapısı
NAND kapısı bu projede temel devre olarak seçildi. Bu paketin Java kaynak kodu yukarda
verilmişti.
5.2 Mantık Kapıları
Diğer mantık kapıları NAND kapıları kullanılarak kolaylıkla oluşturulabilir. NOT kapısı
Şekil 8'de gösterildiği üzre girişlerin birbirine bağlanması gibi kolay bir yolla elde edilebilir.
Parantez içinde verilen sayı, giriş değerinin değişmesiyle çıkışta sonucun tam olarak gösterilmesi
arasındaki en fazla gecikme zamanının, NAND kapısı referans alınarak (NAND kapısındaki
gecikme 1 birim kabul edilerek) oluşturulmuş halidir.
Şekil 8 – NOT kapısı uygulaması (gecikme = 1)
AND kapısı Şekil 9'da da gösterildiği üzre NAND kapısını NOT kapısına bağlayarak elde
edilmiştir.
Şekil 9 – AND kapısı uygulaması (gecikme = 2)
Bir kez daha OR kapısı yapmak için kullanılan kapı sayısını arttırmamız gerekiyor.
Şekil 10 – OR kapısı uygulaması (gecikme = 2)
Şekil 11'de XOR kapısı yapmak için devrenin yapısının biraz daha geliştirilmesi ve
karmaşıklaşması gerektiği görülüyor. Bu devrede dikkat edilmesi gereken bir 'tehlike' durumu
vardır, bazı sinyaller 2 kapıdan geçerek üretilirken bazılari için 3 kapıdan geçilmesi gerekiyor. Bu
yüzden girişteki bir değişiklik çıkışta 2 birim gecikme sonrasında görülebilir, ancak asıl değerine 3
birim gecikme sonra ulaşacaktır.
10
Şekil 11 – XOR kapısı uygulaması (gecikme = 3)
5.3 Çoklayıcılar (Multiplexor)
Şekil 12'de iki tane bir bit giriş sinyali ile bunlar arasında karar vermek için bir seçme
sinyali alan basit bir çoklayıcı görülüyor. Şekil 13'de uygun devre sembolü verilmiştir. Daha genel
söylersek 2^n m-bit giriş için gereken bilgi dağıtıcı (dekoder) ve seçme devresi 5 birim gecikmeli
ve (2^n(1+m)+n+1) kapılı devre gerekecektir.
Şekil 12 – Bir bitlik 2-1 mux uygulaması (gecikme = 3)
Şekil 13 – Bir bitlik 2-1 mux devre sembolü
5.4 Aritmetik Mantık Birimi (ALU – Arithmetic Logic Unit)
ALU birçok alt birimden oluşmuştur. Öncelikle iki tane tek bitlik sayıyı toplayan half adder
(yarı toplayıcı) üniteyi inceleyelim. Tablo 2'de gerekli truth table (gerçeklik tablosu) verilmiştir.
Elde ve toplam terimleri, girişlerin sırasıyla AND ve XOR karşılıklarıdır. Bu sayede yarı ekleyici
basit bir şekilde Şekil 14'teki devre ile oluşturulabilir.
11
A
B Elde Toplam
0
0
0
0
0
1
0
1
1
0
0
1
1
1
1
0
Tablo 2 – Yarı Toplayıcı Gerçeklik Tablosu
Şekil 14 – Yarı toplayıcı uygulaması (gecikme = 3)
Bir bitten daha fazla sayıyı toplarken Tablo 3' te de gösterildiği şekilde daha düşük bitlerden
gelebilecek elde sayısını (carry in) da hesaba katmak gerekir. Elde-tasan (carry out) ve toplam
(sum) ifadeleri karmaşık görünse de iki yarı toplayıcı ünitesiyle Şekil 15'teki gibi kolayca elde
edilebilirler.
A
B Elde Giriş Elde Çıkış Toplam
0
0
0
0
0
0
0
1
0
1
0
1
0
0
1
0
1
1
1
0
1
0
0
0
1
1
0
1
1
0
1
1
0
1
0
1
1
1
1
1
Tablo 3 – Tam toplayıcı gerçeklik tablosu
Şekil 15 – Tam toplayıcı (full adder) uygulaması (gecikme = 6)
12
Bizim yapacağımız ALU'nun sadece toplama işleminden daha fazlasını yapabilmesi
gerekiyor. Çıkartma, AND, OR ve karşılaştırma işlerini de yerine getirebilmeli. Şekil 16'daki tek
bitlik ALU bütün bu işlemleri yerine getirebilir, ki ALU birimi de zaten Şekil 17'de görüldüğü gibi
bunların birbirlerine bağlanmasından oluşur. Artı ile işaretlenmiş kare Şekil 15'teki tam toplayıcı
ünitesi. Ayrıca istenilen sonucun seçilmesi için çoklayıcı kullanıldığına da dikkat ediniz.
Şekil 16 – Tek bitlik ALU uygulaması (gecikme = 15)
Şekil 17'de bir bitlik ALU'ların bağlanmasıyla nasıl 32 bitlik ripple carry ALU'nun elde
edilebileceği gösteriliyor. Operasyon kontrol sinyali; çıkışın, AND kapısı, OR kapısı, toplayıcı ya
da less girişi arasından seçilmesi için kullanılıyor. Çıkartma B girişinin negatifi alınarak yapılıyor.
Negatifleme (tersini alma) ikinin tersi (two's complement) şeklinde, bütün bitlerin terslerinin (NOT)
alınması ve sonrasında 1 eklenmesiyle yapılıyor. Bu ALU birimi içerisinde bütün tek bitlik ALU
üniteleri için binvert hattını 1 yaparak ve ALU0'ın elde değerini 1 yaparak sağlanıyor.
Tek-bit ALU'nun less girişi set-on-less-than (büyüktür / küçüktür) komutu için kullanılıyor.
Son tek-bitlik ALU ünitesi bir önceki toplayıcının çıkışını alan, set adında, fazladan bir çıkışa sahip.
Eğer B'nin A'dan çıkartılması (A-B) negatif bir sonuc verirse (A<B durumunda) son ünitedeki çıkış
değeri 0 olacaktır. Bu yüzden eger A<B ise bütün birimin çıkışı 1, değilse 0 olacaktır.
13
Şekil 17 – 32 bitlik ALU uygulaması (gecikme = 173)
Şekil 18 – ALU sembolü
Dikkat ederseniz ALU için böylesi bir tasarımda gecikme cok büyük. Bunun nedeni tam
toplayıcıları kullanırken elde sayısının ALU0'dan ALU31'e kadar tek tek gelmesini beklemek
zorunda olmamızdır. B0 sinyali ilk ekleyicinin girişine ulaşmak için en fazla 4 gecikmeye uğruyor.
Elde girişten elde çıkışa gecen gecikme 5 birim, elde girişten toplam çıkışına 6 birim. Bu nedenle
son toplam 4+(31x5)+6=165'lik bir gecikmeden sonra sonuca ulaşır. Çıkış çoklayıcıdaki gecikme 5
birim ve sıfırı hesaplamak için gereken ayrıca 3birimlik bir gecikme daha var. Bununla birlikte
ALU içinde başlangıçtan bitişe toplam 173 birimlik bir gecikme söz konusu. Hız carry lookahead
yöntemiyle yükseltilebilir ama bu konumuz dışında. Tek bitlik bir ALU ünitesi için 38 NAND
kapısı gerekiyor. 32 bitlik bütün bir ALU birimi içinse 1200'ün üstünde.
14
5.5 Yazmaç (Register)
Muhtemelen bir işlemci tasarımındaki en önemli bileşenlerden biri veri saklamada kullanılan
yazmaçlardır. Yine modüler bir yaklaşım kullanacağız. Öncelikle D-tipi latchlerle başlayalım.
Şekil19'daki devre D'den giriş bilgisini alıyor ve CK clock sinyali 1 iken Q çıkışına gönderiyor.
Clock sinyali 0 iken çıkıştaki Q değeri, clock tekrar 1 olana kadar bir önceki değerini tutacak.
Şekil 19 – D-tipi latch uygulaması (gecikme = 3)
Bu tam manasıyla tatmin edici bir yöntem değil, çünkü clock 1 iken çıkış değeri Q, girişteki
D değerini alıyor. Bizim tam olarak ihtiyacımız olan, verinin clock'un positif ya da negatif ucunda
girişten çıkışa iletilmesi. Bunu yapmanın bir yöntemi clock'a köşe-tetiklemeli devre eklemek.
Örneğin clock sinyalinin ve tersinin AND'ini alındığında inverterda olusacak gecikmeyle clock'un
positif kenarının tepe noktasında tetiklemeyi sağlayabiliriz.
Yine de bu projede kullanılan tasarım Şekil 20'de gösterilen master slave flip-flop. Clock
sinyali 1 olduğunda ilk latch'in çıkışı giriş değeriyle aynı olacak. Terslenmis clock sinyalinin anlamı
ikinci latch'in bu sürede değişmeyeceğidir. Clock 0 olduğu zaman ilk latch'in değeri sabit kalacak ve
ikinci latch'in değeri ilkinin çıkışı olacak, bu andaki giriş çıkışa yönlendirilecek.
Şekil 20 – Flip Flop uygulaması (gecikme = 4)
Bundan sonra yapılması gereken n-bitlik yazmaç için n tane flip flop'u Şekil 21'deki gibi
paralel şekilde yerleştirmek. Her ne kadar flip flop 11 kapı gerektirse de clock tersleyici ortak
kullanılabilir, böylece 32 bitlik yazmaç için toplamda (32x10)+1 = 321 kapı gerektirecek.
15
Şekil 21 – Yazmaç uygulaması (gecikme = 4)
5.6 Yazmac Dizisi (Register File)
Veri depolamak için genellikle bir dizi yazmaç gerekir. Şekil 22'de gösterilen yazmaç dizisi
32 yazaça sahip. Tek bir clock sinyalinde birine yazıp diğerinden okumak mümkün. Tabiyki yazılan
bir yazmaç aynı anda okunuyorsa çıkış verisinin doğruluğu garanti edilemez. Sunulan gecikme
clock değişimiyle verinin okumaya hazır olması arasında bir değer. Geleneksel olarak Yazmaç0, 0'a
bağlanır. Bu yazmaçtan okuma yapıldığında 0 okunur, ve yazma işleminden etkilenmez.
Şekil 22 – Yazmaç dizisi (gecikme = 11)
16
5.7 Bellek (Memory)
Her ne kadar bu proje işlemci tasarımıyla ilgili olsa da işlemcinin herhangi bir pratik
kullanımı için veri ve komut belleğine bağlı olması gerekir. Yaygın olarak kullanılan 2 tip bellek
mevcuttur, SRAM ve DRAM. Burada hafıza birimlerinin ayrıntılarına değinmeyecegiz ancak
mimarimizde bulunan diğer birimlerle iletişim kurmaları yüzünden okuma/yazma gecikme süresine
ihtiyacımız var. Bellek ve bağlantılı olarak bellekten veya belleğe veri aktarımı yavaştır ve bu
yüzden bizde hafızaya ALU değeriyle aynı olan 180 birimlik bir gecikme atıyoruz.
5.8 Bileşen Soyutlama
Bazı birimlerin hızları, tasarımlarındaki çok sayıda kapıdan dolayı yavaş. Bu nedenle
simulasyon dosyalarıyla eşdeger java sınıf dosyalarını yaratırken daha yüksek seviyede bir
soyutlama yapıldı, paketin çıkış bağlantısı için tampon kullanımı gibi. Addoutput() metodu bu
bağlantıdan herhangi bir çıkış sinyaline eklenen gecikmeyi ifade eden fazladan bir değişken alabilir.
Bu soyutlamayı kullanarak simulasyonlardan belli bir miktar ayrıntıyı kaybediyoruz.
Örneğin her ne kadar gecikmeyi simule ediyor olsak da çıkışlarda yarış durumu oluşmamaktadır.
Aşağıdaki kod bu yöntemle yazmaç dizisinin nasıl oluşturulduğunu gösteriyor.
class RegisterFile extends Package {
private boolean previousClock;
public Binary registers[];
public void construct() {
addInput("RegWrite", 1);
addInput("ReadRegister1", 5);
addInput("ReadRegister2", 5);
addInput("WriteRegister", 5);
addInput("WriteData", 32);
addInput("Clock", 1);
// Note delay of 11 on outputs
addOutput("ReadData1", 32, 11);
addOutput("ReadData2", 32, 11);
}
// Initialise all registers to be empty
public void initialise() {
registers = new Binary[32];
for (int i = 0; i < 32; i++) {
registers[i] = new Binary(32);
}
}
public void simulate() {
// Check for negative going edge
if (previousClock && !getInput("Clock", 0)) {
// Set outputs to values of requested registers
setOutput("ReadData1",
registers[getInput("ReadRegister1").intValue()]);
setOutput("ReadData2",
registers[getInput("ReadRegister2").intValue()]);
// Check if RegWrite high and not writing to Register0
if (getInput("RegWrite", 0) &&
17
(getInput("WriteRegister").intValue()!=0)) {
// Write input to register
registers[getInput("WriteRegister").intValue()] =
getInput("WriteData");
}
}
previousClock = getInput("Clock", 0);
}
}
6. Sadeleştirilmiş MIPS Komut Seti
Takip eden işlemcinin komut seti MIPS mimarisinin bir alt seti olarak tasarlandı. İlk RISC
MIPS longası John Hennessy tarafından 1981 yılında Standford'da tasarlandı ve üretildi. Bizim
uygulamaya koyacağımız komutlar Tablo 4'de özetlenmiştir. Bu komutlar bir takım tasarım
problemlerinin incelenmesi ve basit bir programın uygulanması için yeterlidir.
Instruction
Example
Meaning
add
add $1, $2, $3
$1 = $2 + $3
subtract
sub $1, $2, $3
$1 = $2 - $3
and
and $1, $2, $3
$1 = $2 & $3
or
or $1, $2, $3
$1 = $2 | $3
load word
lw $1, 100 ($2) $1 =Memory[$2+100]
store word
sw $1, 100 ($2) Memory[$2+100] = $1
branch on equal beq $1, $2, 100
if ($1==$2) go to PC+4+(4×100)
set on less than
slt $1, $2, $3
If ($2 < $3) $1 = 1 else $1 = 0
jump
j 10000
go to 10000
Tablo 4 – Basitleştirilmiş MIPS Komut Seti
Dolar işaretiyle gösterilen sayılar yazmaç dizisindeki yazmaçları belirtiyor. Bu RISC
mimarisinde anahtar bir özellik. Hafıza erişimi yavaş olduğu için, işleme hızı, sayılar işlemci
içindeki yazmaçlarda tutarak arttırılmıştır. Load ve store hafızaya bağlanılan tek komutlar. Diğer
bütün komutlar işlemleri yazmaçlar üzerinde yapıyor. Bu bizi basitleştirilmiş komut yapısına
götürüyor. 32 bit MIPS formatlarının üçü de projedeki tasarım tarafından destekleniyor.
7 Tek-Döngülü İşlemci
Tasarıma 3 komut setinin herbiri için gerekli veriyolu ile başlayabiliriz. Bu her komut için
işlem tek bir clock sinyali sürecektir.
7.1 Komut Alımı (Instruction Fetch)
Komut alımı bütün komut formatları için ortaktır. Basitleştirmek için komut ve veri
belleklerini ayırıyoruz. 32-bitlik program sayacı (PC – program counter) adındaki yazmaç,
hafızadaki bir sonraki komutun adresini tutar. Yazmaç komutun hafızadan okunduğu sürece sabit
kalmasını sağlar. Her komut 4 bytedan oluştuğu için bir sonraki komuta erişmek için program
18
sayacını her clock'da bu kadar arttırmamız gerekir. Şekil 23 bu işlemin yapılması için gereken basit
bir devreyi içeriyor.
Şekil 23 – Komut alma
7.R-Format Komuları
Döngünün bir sonraki aşaması komutun anlaşılması, çözülmesi ve gerekli veriyolunun
ayarlanmasını gerektirir. R-format komutları aritmetik ve mantıksal işlemler için kullanılır. Tablo 5
komutları içeren alanları gösteriyor. Bütün R-format komutlar için opcodelar aynıdır.
Alan Bits
Anlamı
op
6
opcode(000000)
rs
5
İlk kaynak yazmacı
rt
5 İkinci kaynak yazmacı
rd
5
Hedef yazmacı
shamt
5
Kaydırma miktarı
funct
6
Aritmatik/mantık fonksiyonu
Tablo 5 – R-Format Komut Alanı
Tablo 6'da örnek bir komut görülüyor, add $1,$2,$3. Her aritmetik/mantık işleminin onunla
bağlantılı bir fonksiyon kodu bulunur. Komutların sabit format olması sayesinde gerekli alanların
düzenlenmeleri çok kolaydır.
op
rs
rt
rd
shamt
funct
000000 00010 00011 00001 00000 100000
Tablo 6 – add $1, $2, $3 işlemi için gereken komut
19
İki farklı kaynak yazmacından veri alıp bir ALU işlemi uygulayıp sonrasında elde edilen
veriyi 3. bir yazmaca yazmak bütün R-format komutlarda aynı olan uygulamadır. Bu işlem için
gereken veriyolu Şekil 24'de verilmiştir.
Şekil 24 – R-Format veriyolu
7.3 I-Format Komutları
I-format komutları veri transferi ya da dallanma (branch) gibi hızlı adres gerektiren
işlemlerde kullanılır. Tablo 7'de komutların formatı verilmiştir. Burada opcode tek başına belirli bir
işlemi tanımlamak için kullanılmıştır.
Alan
Bitler
Anlamı
op
6
adres
rs
5
İlk kaynak yazmacı
rt
5
İkinci kaynak yazmacı
adres/hızlı
16
Adres ya da hızlı değer
Tablo 7 – I-Format Komut Seti
Son alan, yükleme ve kaydetme işlemlerinde ilk yazmaçta bulunan gerekli adres bilgisinin
ofsetini içerir. Bu adres düzenlemeyi kolaylaştırır. Veri ikinci yazmaçtan hafızaya kaydedilir ya da
ikinci yazmaca yüklenir. Örnek bir komut Tablo 8'de verilmiştir.
op
rs
rt
adres/hızlı değer
100011 00010 00001 0000000001100100
Tablo 8 - lw $1, 100($2) işlemi için komut seti
Her iki komutta RS yazmacından adresi okumayı ve ofset eklemeyi gerektiriyor. Bu ekleme
işlemi için ALU ofsetin işaretli 32 bit genişletilmesiyle kullanılabilir. Kaydetme işlemi için RT
yazmacındaki veriyi okuyup belirtilen adrese yazmak isterken, yükleme işlemi için belirtilen
adresten verinin okunup RT yazmacına yazılmasını istiyoruz. Bu işlem için gereken veriyolu
Şekil25'te gösterilmiştir. Yazmaçlar ve veri hafızası için gereken okuma ve yazma sinyallerinin
üretilmesi kontrol biriminin görevidir.
20
Şekil 25 – Yükleme / Kaydetme veriyolu
Tablo 9'da verildiği gibi ikinci bir tür I-format komutu için dallanma komutunu dikkate
almamız gerekiyor. Burada iki yazmacın içindeki verinin karşılaştırılması ve aynı büyüklükte
olmaları durumunda sayının ofsette belirtilen komuta dallanması istenmektedir.
op
rs
rt
adres/hızlı değer
100011 00010 00001 0000000001100100
Tablo 9 - beq $1, 100 işlemi için komut seti
Bunun için gerekli olan veriyolu Şekil 26'da verilmiştir. Veri iki yazmaçtan da okunuyor ve
ALU bir çıkarma işlemi gerçekleştiriyor. ALU'nun 0 çıkışı dallanma kontrol birimi tarafından
dallanmanın olup olmayacağını kontrol etmek için kullanılabilir. Dallanma için olan hedef adresi
adres/hızlı alanının işaret genişletilmesi hesaplanır, sonrasında sola doğru 2 kere kaydırılarak
ofsetin byte değeri elde edilir. Bu daha sonra PC+4 değerine eklenir.
Şekil 26 – Dallanma veriyolu
21
7.4 J-Format Komutları
Bu 3. komut formatı yalnızca JUMP işlemi icin kullanılır. İki alan ve örnek bir komut
uygulaması Tablo 10 ve Tablo 11'de sırasıyla verilmiştir.
Alan
Bitler
Anlamı
op
6
Opcode (000010)
Hedef adres
26
Sıçrama yapılması istenen adres
Tablo 10 – J-Format Komut Seti
op
Hedef adres
000010 00000000000000100111000100
Tablo 11 – j 10000 için gereken komut
Bu işlem için veriyolu önemsiz. JUMP işlemi için tek ihtiyacımız olan sey PC'nin atlanması
gereken adrese ayarlanması. Bir kez daha burada verilen adres byte şekilinde ancak kaydırmadan
sonra bile sadece 28 bitlik bilgi içeriyor. Geri kalan 4 bit (PC+4)'ün üst 4 bitinden alınacak.
7.5 Veriyollarının Bağlanması
Şimdi bütün yapılması gereken veriyollarının ve üç tip komutun birleştirilmesi. Bu işlem
çoklayıcı ve kontrol birimi ile yapılıyor. Sekil 27'de gösterilen ana kontrol birimi alınan komuttan
opcode'u ayırıyor ve çözümlüyor. Daha sonra verilen komut için gerekli olan veriyolunu
çoklayıcıların seçme bitleri ile belirliyor ve yazmaçlar ve belleğin yazma/okuma bitlerine gerekli
sinyalleri hazırlıyor. Tablo 12 her komut seti için gereken 10 kontrol hattını gösteriyor. Sadece 5
opcode'un ayrıştırıldığı bu basit tasarımda kontrol birimi mantık kapıları ya da programlanabilir
mantık dizini (PLA – Programmable Logic Array) ile oluşturulabilir.
Komut
Reg
Dst
ALU Mem
Src toReg
Reg
Write
Mem
Read
Mem
Write
R-format
1
0
lw
0
sw
Branch Jump
ALU
Op
0
1
0
0
0
0
10
1
1
1
1
0
0
0
00
X
0
X
0
0
1
0
0
00
beq
X
0
X
0
0
0
1
0
01
j
X
X
X
0
0
0
0
1
XX
Tablo 12 – Kontrol Sinyalleri
ALU kontrol birimi ALU için gereken bnegate ve işlem sinyallerini üretiyor. Bunu yapması
Tablo 13'de gösterildiği gibi kontrol biriminden alacağı sinyallere bağlı.
22
ALUop
İstenilen İşlem
00
Topla
01
Çıkar
10
Fonksiyon kodu
kullan
Tablo 13 – ALUop kontrol sinyali çözümleme
Dallanma kontrolü 1 yapıldığında dallanma gerekmektedir ve ALU çıkışı 0 olur. Bu test
basitçe AND kapısıyla yapılabilir.
23
Şekil 27 – Tek döngülü işlemci
24
7.6 Simulasyon
Devre artık Şekil 28'de gösterildiği haliyle simulasyona girmeye hazır. (Kullanıcının
isteyeceği şekilde görülmeyeceğinden açıklayıcı bazı notlar eklenmiştir.) Temel bileşenlerle birlikte
kontrol ünitesi gibi özelleşmiş bileşenler NAND kapılarından oluşturulmuş ve testlerin ardından
Java sınıf dosyaları haline dönüştürülmüşlerdir.
Şekil 27'deki devreye yapılan tek ek sol alt köşede görülen clock'tur. Verinin devre boyunca
soldan sağa doğru kayıpsız geçtiğinden emin olmak için clock 5 alt birime bölünmüştür.
Şekil 28 – Tek döngülü işlemci simulasyonu
Simulasyon Tablo 14'deki, belleğin 4. ve 8. konumundan sayı alan, arka arkaya toplama
şeklinde çarpan ve sonrasınra 12. bellek konumuna kaydeden programla test edildi. Hızlı toplama
ya da çıkartmayla iligili bir komut eklemediğimiz icin 0. hafıza birimi program tarafından
kullanılan 1 değerini içeriyor.
Tablo 14 – Çarpma işlemini yapacak program
Şekil 29 programın, simulasyonun komut hafızasına yazıldığını, Şekil 30 2 ile 3' ün
çarpımının sonucunu gösteriyor.
25
Şekil 29 – Çarpma hafızasını bulunduran komut belleği
Şekil 30 – Sonucu (2x3=6) içeren veri hafızası
7.7 Kritik Yol
Pekte verimli olmayan bu tasarım, sadeliği için tercih edildi. Verilen komutların işlemci
tarafından yapılması için gereken süre aşağıdaki formülle hesaplanabilir:
işlemci yürütme zamanı = komut sayısı x komut başına döngü x clock döngü süresi
Her ne kadar komutlar tek bir clock sinyali sürsede, clock süre olarak oldukça uzun. Sabit
clock hızı en uzun süren işlemin yapılmasına yetecek kadar uzun olmalı. Komut yüklemedeki kritik
yol, komutun alımı, bir yazmaca erişim, bir ALU işlemi, hafıza erişimi ve başka bir yazmaç
erişimini içeriyor. Pek çok tasarımda olduğu gibi her alt clock döngüsü sabit ve eşit uzunlukta ki bu
da toplamda 5x186=930 birimlik gecikme anlamına geliyor.
Yürütme zamanını düşürmenin bir yolu CISC mimarisin de kullandığı gibi komut sayısını
azaltmaktır. Her birinin çok özelleşmiş bir işlem gerçekleştirdiği karmaşık bir komut seti
kullanılabilir. Bu durum gereğinden fazla komutun oluşmasına yol açabilir ki bu durumda gerekli
kontrol sinyallerini üretmek için gereken çözme işlemini çok karmaşık bir hale getirebilir. Karmaşık
26
komutların süresinin, daha basit komutların aynı işlem için harcadıkları süreden daha fazla
olmamasına dikkat edilmesi gerekir.
8 Çoklu Döngülü İşlemci
MIPS RISC komut setiyle çalıştığımızdan asıl amacımız süreyi düşürmek (komut başına
döngü x clock döngü süresi). Bunun için komut yürütmesini Tablo 15'deki gibi parçalara bölebiliriz.
1 Komut alınması
2 Komut çözümlenmesi ve yazmaç erişimi
3 Uygulama / Yürütme, bellek adresi
hesaplama ya da dallanma işlemi
4 Hafıza erişimi ya da R-tip işlem
5 Yazmaca geri yazılım
Tablo 15 – Çoklu Döngü Aşamaları
Başta bunun pek bir kazanç sağlamayacağı düşünülebilir. Bu yeni durumda her komut icin 5
döngümüz ve öncekinin 5'te 1'i kadar döngü clock süremiz var, o zaman bir fark yok gibi görülüyor.
Ancak böyle değil, çünkü sadece load komutu bütün 5 aşamayada ihtiyaç duyuyor. Örneğin jump
komutu için ilk 3 asama yeterli olacaktır. Bu sayede ortalama olarak komut başına döngü sayısı
5'ten az olacağında yürütme zamanında azalma söz konusudur.
8.1 Veriyolu
Şekil 31'e bakınca ilk dikkat çeken nokta hem veri hem de komutlar için tek bir hafıza
biriminin olması ve bütün aritmetik işlemler için tek bir ALU ünitesinin kullanılıyor olması. Silikon
yüzeyindeki her azalma longa fiyatında düşüş ya da boş alanın hızı arttırmak için on-board catch
gibi başka ekipmanlar için kullanılabilmesi anlamına gelir.
1. İlk olarak PC adresi hafızadan bir sonraki komutu almak için kullanılıyor. Uygulanan
komut, komutun yürütülmesi sırasında hafıza yeniden kullanılabilir diye yeni bir yazmaçta
saklanıyor. ALU girişindeki çoklayıcı 4 eklemek üzre ayarlı ve sonuç tekrar PC üzerine yazılacak.
2. Opcode çözülmek üzre kontrol ünitesine giderken iki yazmaçtaki veri okunuyor. Aynı
zamanda dallanma adreside komutun en küçük 16 bit'i işaret genişletilerek ve kaydırılarak
hesaplanıyor. ALU bir sonraki aşamada farklı işler için kullanılacağından adres hedef yazmacına
yükleniyor. Veri ve/veya dallanma adresi daha sonra kullanılmayacak dahi olsa herhangi birşeyi
kaybetmek istemediğimizden, hesaplanıp saklanıyor, eğer sonradan kullanılmaları gerekirse hazır
olacaklar.
3.Eğer R-formatında bir komutu uyguluyorsak, ALU çoklayıcıları iki veri nesnesini seçecek
ve ALU gerekli işlemi yapacak. Bir dallanma komutunda hesaplanan hedef adresinin PC'ye yazılıp
yazılmayacağına karar vermek için veri çıkarılacak. Yükleme ya da kaydetme komutu için işareti
genişletilmiş ofseti ilk yazmaca eklenecek. Jump komutu PC'ye yazılma işlemiyle birlikte
tamamlanmış oluyor.
4.Yükleme, kaydetme işlemleri yazılımı, ya da hafızadan okuma ya da R-format komutların
hedef yazmaçlara yazımı.
5. Yükleme komutu istenilen yazmaca geri yazılımı.
27
Şekil 31 – Çoklu döngülü işlemci
28
8.2 Kontrol Birimi
Tahmin edileceği üzre çoklu-döngü veriyolunun kontrol ünitesi tekli-döngü versiyonuna
kıyasla çok daha karmaşık bir yapıya sahip. En kolay şekilde Şekil 32'de görüldüğü gibi bir akış
diyagramıyla gösterilebilir. Bu mantık birimini yapmak için pek çok yol olabilir ancak hepsi
Şekil33'de görülen finite state machine temellidir. Giriş verileri opcodelar ve mevcut state bilgisi,
çıkışlar ise kontrol sinyalleri ve bir sonraki state. 10 state'i temsil etmek için 4 bite ihtiyacımız var.
17 kontrol sinyali toplam çıkış sayımızı 21'e yükseltiyor.
Şekil 32 – Kontol sinyallerinin akış şeması
29
Şekil 33 – Finite state machine
8.2.1 Read Only Memory (ROM)
En basit uygulama için dahi gerekecek en küçük ROM 2^10x(17+4)=21KBitlik olacaktır.
Biz 2^6 olası opcodun sadece 5 tanesiyle ilgilendiğimiz için truth (gerçeklik) tablomuz oldukça
seyrek olacak, bu yüzden de ROM'un büyük kısmı kullanılmayacak. Yine de dikkat edilirse 17
kontrol sinyali sadece mevcut state'e bağlı, bu durumda bu kısmı 2^4x17=272 bitle ifade edebiliriz.
Sonraki state hem mevcut state hem de opcode'a bağlı olduğundan bu kısımda 2^10x4=4096 bit
gerekiyor. Bu yüzden tabloyu ikiye bölmemiz halinde ihtiyaç duyulan alanın 4.3kbite düşeceği
görülüyor. Bu azaltmaya rağmen hala kullanılmayan alanlar mevcut. Bunun nedeni pek cok giriş
kombinasyonuyla statelerin hiçbir zaman oluşmaması ve genellikle 0 state'inde opcode'un ne
olduğunun bir önemi olmaması.
8.2.2 Programlanabilir Mantık Dizisi (PLA)
Seyrek bir truth tablosunda PLA daha verimli bir sonuç sunuyor. Bir PLA'nın toplam
büyüklüğü (#giriş * #ürün terimi) + (#çıkış * #ürün terimi) ile orantılı. Bu uygulamada 18 ürün
terimi var (opcode ve statelerin kombinasyonları), bu sayede ihtiyaç duyulacak PLA büyüklüğü
(10x180) + (21x18) = 558 olacaktır.
ROM uygulamasında olduğu gibi PLA'yı da ikiye bölmek mümkün. Kontrol sinyallerini
üretecek PLA her state için tek ürün terimine ihtiyaç duyacağından büyüklüğü (4x10)+(17x10)=210
olacaktır. İkinci PLA ise geri kalan ürün terimlerini alacak ve sonuç olarak (10x8)+(4x8)=112
büyüklüğünde olacak. Toplam olarak 322 PLA hücresi ediyor ki ROM uygulamasına kıyasla çok
büyük bir gelişme.
30
8.2.3 Belirgin (Explicit) Sonraki State
Her ne kadar PLA bizim kısa komut setli küçük uygulamamız için başarılı bir çözüm yolu
sunsada daha cok komut eklememiz durumunda state sayıları ve ürün terim sayısı hızla artacaktır.
Her iki uygulamada da görüldüğü gibi kontrol ünitesinin büyük kısmı sonraki state'i hesaplamak
üzerine çalışıyor. Daha karmaşık bir komut setiyle Şekil 32'de görüldüğü gibi 2,3,4 gibi daha çok
dizi görülecektir. Bundan bir avantaj sağlamak için mevcut state'i tutan yeni bir yazmaç tanıtıyoruz.
Sonraki state'i içeren çıkış sinyalleri yerine Tablo 16'daki iki bitlik kontrol kodunu kullanıyoruz.
Şekil 34' deki adres seçme ünitesi gelecek state'i kontrol etmek için bu kontrol kodlarını kullanıyor.
İki hızlı ROM, state bir ve ikideki karar noktalarına uygulanıyor. Bunlar giriş olarak opcode alıp,
çıkış olarak sonraki state'i oluşturuyorlar.
AddrCtl Değeri
İşlem
00
State = 0
01
ROM 1 ile yönlendirme
10
ROM 2 ile yönlendirme
11
Yükseltme State'ini kullan
Tablo 16 – Adres Seçme Sinyalleri
Şekil 34'deki devre artık daha çok işlemcinin komut alma ve dallanma kısmı gibi görünüyor.
Bu bizi state yazmacımızın, bir mikroprogram sayacı ve PLA ya da ROM mikrokodu içeren bir
ortam olduğu microkod kavramına getiriyor.
Şekil 34 – Net sonraki state'li kontrol birimi
31
8.3 Simulasyon
Şekil 31'deki devre belirgin sonraki state kontrol birimiyle birlikte simulasyona girildi.
Tamamlanmış devre Şekil 35'de görülebilir. İki fazlı clock, kontrol sinyallerinin veri transferinden
önce hazırlandıklarından emin olmak için hala gerekli. Kontrol biriminin, state'i, mevcut komutun
gerektirdiğini kontrol akış diyagramındaki gibi yapılıp yapılmadığından emin olmak için Şekil
36'daki gibi görülebilir.
Tek döngülü versiyondaki program, adreslerinin değistirilerek program kodunun sonrasına
eklenmesi dışında aynen kullanıldı.
Şekil 35 – Çoklu – döngülü işlemci simulasyonu
Şekil 36 – Kontrol ünitesi state'i
Tek clock döngüsündeki kritik yolun şimdiki gecikmesi 192 birim. Tablo 17'deki komut
dağılımları uygulandığı taktirde ortalama 4,07 clock döngüsünde bir komut işlemi görülüyor. Bu
ürün (komut başına döngü x clock döngü süresi) bu sayede 781'e düşürüldü. Özellikle donanımın da
azaltıldığı göz önünde bulundurulduğunda çok başarılı bir azalma.
32
Komut
Sıklık Clock Sinyali Sayısı
Load
32%
5
Store
17%
4
R-Format 38%
4
Branch
10%
3
Jump
3%
3
Tablo 17 – Komutların Kullanım Sıklıkları
9 İş Hatlı (Pipelined) İşlemci
Komut döngüsünü parçalara böldüğümüzde komutların işlenmesi Şekil 37'de görüldüğü gibi bir
şekilde yürütülür. İlk komut çözümlenme/yazmaç alma aşamasına geldiğinde ikinci komutun
alınması mantıklı bir hamle olacaktır. Benzer şekilde ilk komut ALU aşamasına geldiğinde ikincinin
çözümlenme aşamasına geçmesi, üçüncü bir komutun alınması da. Bu pipelining olarak adlandırılır
ve Şekil 38'de gösterilmiştir. Bunun avantaji, her ne kadar her komut hala 5 döngüde bitiriliyor olsa
da her clock sinyaliyle yeni bir komutun alınabilmesidir. Bu sayede çok sayıda komutun olduğu
durumlarda her komut tek bir döngüde yapılıyormuş gibi olacaktır.
Şekil 37 – İş hatsız durum
Şekil 38 – İş hatlı durum
Yürütme döngülerinin farklı aşamaları (farklı komutlar olmasına rağmen) eş zamanlı olarak
yapmayı umduğumuza göre, tek döngülü mimariye dönüp oradan ilerlemek daha anlamlı
görünüyor. İlk olarak belirtilmesi gereken nokta, bir aşamadaki çıkışın, bir sonraki komutu önceki
yapılmış gibi yaparken, sabit kalmağıdır. Bunun çözümü her 5 aşama arasına yazmaçlar
yerleştirmektir.
Kontrol birimi çoklu-döngü versiyonunda büyük bir değişiklik yapılmaksızın aynen
kullanılıyor. Gereken kontrol sinyallerinin bu yazmaçları kullanarak bir aşamadan diğerine
taşınması sayesinde belli bir komutun kontrol sinyalleri, mevcut olarak yürütülen komut ile aynı
aşamada kalacak.
Gerekli hedef yazmaçlarının adreslerinin yüklenecek veriyle aynı zamanda yazmaca
ulaşmasına dikkat edilmeli. Bu yüzden öncelikle ara yazmaçlara gönderilip sonrasında yazmaç
dizisine geri dönmeliler. Eşdeğer devre Şekil 39'da verilmiştir.
33
Şekil 39 – Pipelinelı işlemci
34
9.1 Veri Riski
Bu devreyle ilgili iki problem var. İlki veri riski adıyla biliniyor. Bu durum bir komutun belli
bir yazmaca yazması sırasında henüz yazma işlemi bitmemişken başka bir alt aşamanın aynı
yazmacı okumaya calışması sırasında oluşur. Bu sorun için iki muhtemel çözüm yolu mevcuttur.
İlki derleyicinin böyle birşey olmamasını sağlamasıdır. Bu ifadelerin düzeninin tekrar ayarlanmasi
ve/veya aralarına nop (no operation) komutu koyarak sağlanabilir. Diğer yöntem ise riskin
donanımsal olarak tespiti ve okuma teşebbüsünün risk ortadan kalkıncaya kadar durdurulmasıdır.
Araya nop komutunun konması ya da iş hattı (pipeline) 'ın durdurulması işlemcinin
verimliliğini düşürecektir. Bunun etkisi bir yere kadar içsel yönlendirmeyle azaltılabilir. Bu her ne
kadar bir işlemin sonucu/cevabı bir yazmaca kaydedilmemiş olsa da hesaplanmış olduğu gerceğine
dayanır.
Bu yüzden sonuç pipeline içinde bulunduğu yerden ihtiyaç olan yere "yönlendirilebilir". Her ne
kadar çok zekice bir yaklaşım olsa da yükleme komutundaki durumlarda yönlendirme, sorunu
çözemez. Bu tip durumlarda, istenilen hafıza konumu okunana kadar beklemek zorundayız.
9.2 Dallanma Problemi
Diğer bir risk unsuru da dallanma durumunda karşımıza çıkıyor. Dallanmayı takip eden bir
komutta ne yapacağız? Eğer dallanma koşulu oluşmazsa onları yürütmek istiyoruz, eğer oluşuyorsa
istemiyoruz.
Bu konuyla ilgili 3 çözüm yolumuz var. İlki önceki gibi nop komutu koymak. İkincisi
dallanma kararı verile kadar iş hattı (pipeline) 'nı durdurmak. Bu durumlarda açıkca görüldüğü gibi
pekçok clock döngüsü kaçırılacaktır. Tablo 17'de görüldüğü üzre komutların %10'u dallanmadır ve
bu
tutum bizim toplam yürütme zamanımız açısından hiç de iyi olmayacaktir. 3. strateji dallanmanın
olmayacağını varsayarak işleme devam etmektir. Eğer dallanma olmazsa biz bir sonraki komutta
işleme başladığımız için kazançlıyız. Dezavantajımız ise dallanma olması durumunda devreye
eklenmesi gereken fazladan yapılardır. Tahminimizin tutmaması durumunda dallanmayı izleyen
komutları bütün kontrol sinyallerini 0'a çekerek iş hattından atmamız gerekmektedir.
9.3 Simulasyon
Simulasyonu sade tutmak amacıyla risk oluşturabilecek durumlar görmezden gelinmiştir.
Bu, sorumluluğu bu tip durumların oluşmamasından emin olmak için, gerekli yerlere nop komutunu
eklemesi gereken 'derleyici' üzerine yüklüyor. Mid-simulasyondaki işlemci Şekil 40'da görülebilir.
35
Şekil 40 – İş hatlı (pipelined) işlemci simulasyonu
Yeni işlemcide çalışması için çarpma programımızı Tablo 18'deki şekilde yeniden yazmamız
gerekiyor. Her ne kadar programın uzunluğu 2 katına çıkmış olsa da aklımızda tutmamız gereken
hızdaki 5 kat artıştır. Pipeline kullanarak ortalama komut süresi 184 birime düşürülmüştür.
lw $1, 0 ($0)
lw $3, 8 ($0)
lw $2, 4 ($0)
nop
nop
sub $3, $3, $1
add $4, $2, $4
nop
nop
beq $0, $3, 1
nop
nop
nop
j 3
nop
nop
sw $4, 12 ($0)
Tablo 18 – İş hatlı (pipelined) Çarpma Programı
Nop komutlarının yanı sıra diğer ifadeleri de yeniden düzenledik. 1 ve 3 yazmaçlarının önce
yüklenmesi çıkartma işleminin öbür türlü yapabileceğimizden 1 döngü öncesinde yapmamıza
olanak sağlar. Toplama komutu aslında çıkartma ve dallanma arasında herhangi 3 döngüde
yapılabilir. Tablo 17'de belirtildiği gibi programımızda daha fazla sayıda R-format komutu varsa
36
bunlar boşlukların çoğunu doldurabilir. Gerçektende dallanma hatalarının önüne geçmek, azaltmak
için kullanılan diğer bir yöntem dallanmadan önceki dallanmayı etkilemeyen komutları
dallanmadan sonraki boşluklara yerleştirmektir. Bu şekilde yapılmasını istediğimiz işlemler her
halikarda yapılacağından dallanmaya girilip girilmemesinin bir önemi kalmamış olur.
10. Sonuç
Projenin ana hedefi olan genel kullanımlı, kullanımı kolay bir dijital simulatorun tasarım,
yapılma ve test aşamaları net bir şekilde tamamlandı. Bu devrelerin tasarlanmalarını ve simule
edilmelerini olanaklı kıldı.
Bir problem hala duruyor ki o da simulasyon hızı. Aynı işi yapan class dosyalarının
devrelerin yerine konmasıyla bu konuyla ilgili sorun çözülmüş olsa da bu paketlerin de simulasyon
sırasında içeriklerinin görülmesi ve neyin nasıl çalıştığının incelenmesi daha güzel olurdu. Her ne
kadar simulatörü hızlandırmak için olası geliştirmeler mümkünse de problemin asıl kaynağı
Java'nın bir yorumlama (interpreted) dili oluşudur. Bu yüzden biz aslında Java sanal makinesini
simule eden bir bilgisayarda işlemci simulasyonu yapıyoruz. Win 95 için olan Just In Time (JIT)
derleyicisinin kullanımı sorunları önemli ölçüde giderdi. Yine de JIT derleyicileri daha az nesne
olduğunda çok daha etkili ki bu bizim simulasyon yapımıza uygun olan durum değil. Belki Sun'ın
çıkarmayı düşündüğü Hotspot derleyicisi daha başarılı bir performans sunar.
Benim simulasyona eklenmiş olmasını isteyeceğim birkaç özellik daha var. Öncelikle
paketin içinde bulunduğu state veya devrenin kaydedilebilmesi çok yararlı olurdu. Örneğin bu
komut hafızasına farklı programlar yüklenmesine olanak tanırdı.
İkinci bir güzel özellik de simulasyon sırasında daha çok etkileşime olanak tanınabilmesi
olurdu. Örneğin test edilen bileşenin bağlanmamış girişlerinin değiştirilebilmesi. Eğer state
göstergeleri değerlerin değiştirilebilmesine olanak verecek şekilde değiştirilseydi (simulasyon
dururken) bu programın değişmesine ve PC gibi yazmaçların istenilen / belirli değerlere
kurulmasına olanak sağlardı.
Başka güzel bir özellikte bilgisayarın otomatik olarak verilen giriş ve çıkış arasındaki
gecikmeyi hesaplayabilmesi olabilir. Düzenleme özelliği de geliştirilebilir, tabi bu swing sürükle
bırak sınıfı bitirildiğinde çok daha kolay yapılabilecektir.
Bu projedeki 3 mimarinin simulasyonu komut başına döngü ve döngü uzunluğu arasındaki
bağlantıları çok iyi gösterdi. Aynı zamanda iş hattı uygulaması (pipelining) gibi şemalardaki
zorluklar konusunda da aydınlattı. Simulasyonların geliştirilerek işlemci tasarımı sırasında
incelenebilecek sayısız farklı nokta vardır. İş hattı uygulanmış bir işlemciye risk tespit özelliğinin
eklenmesi nispeten kolay bir sorun olurdu. Örneğin bizim burada değinmediğimiz, RISC
mimarisinin başka bir temel özelliği SPARC, üstüste binen pencere yazmaçları gibi yordam çağırma
mekanizmaları iyi bir deneme alanı olur.
Sonuç olarak önceden belirtilmiş olan dijital bir simulasyon paketinin tasarlanması ve
yapılması, sonrasında bu simulasyon kullanarak işlemci tasarlanması hedefleri yerine getirilmiştir.
Süreç boyunca ben birçok şey öğrendim. Konuyla ilgili yaptığım araştırmalar sayesinde RISC
işlemcilerle ilgili yanlış anlamalarımı düzeltme imkanı buldum. Gelecekte başlangıç aşamasındaki
ve beta sürümü çıkartmaya çekinen bir programlama dili kullanmadan önce iki kere düşüneceğim.
Bir diğer önemli derste hedefleri, mantıklı bir neden olduğu sürece değistirmekten korkmamak
gerektiğidir. Bunu söylerken geri dönüp projeye baktığımda yapmış olduğumdan daha farklı
yapacağım pek birşey göremiyorum.
37
11 Referanslar
Patterson & Hennessy, Computer Organization & Design : The Hardware / Software
Interface, Morgan Kaufmann, 1994
Tanenbaum, Structured Computer Organization (Third Edition), Prentice Hall, 1990
Hennessy & Patterson, Computer Architecture : A Quantitative Approach (Second Edition),
Morgan Kaufmann, 1996
Flanagan, Java in a Nutshell (Second Edition), O'Reilly, 1997
Hill & Peterson, Digital Logic and Microprocessors, Wiley, 1984
Clements, The Principles of Computer Hardware (Second Edition with corrections), Oxford
University Press, 1992
Ek - A - İlerleme / Süreç Raporu
A.1 Projeye Genel Bakış
Projenin amacı işlemci simulasyonunda yapılabileceği bir dijital devre simulatorunun
tasarım, yapım ve test edilmesidir. Özellikle CISC ve RISC islemciler arasındaki temel mimari
farklılıklar karşılastırılacak ve incelenecektir. Aşağıda bulunan RISC özellikleri ayrıntılı olarak
incelenmiştir.
* Mikro programlamanın olmaması
* Tek clock döngülü komutlar
* Pipelining
* Üstüste binen yazmaç pencereleri
Devreler mantık kapıları seviyesinden yapılacaklardır. Bileşenler modüler bir yaklaşım
amacıyla paketler halinde oluşturulacaktır. Umut ediyoruz ki bu, iki tasarım arasında, büyük
oranlarda tekrar kullanıma olanak sağlayacaktır. Yine de işlemci simulasyon hızının yükseltilmesi
için modüllerin daha yüksek seviye bir soyutlamayla tekrar yazılmaları gerekebilir.
A.2 Hedefler
Projenin hedefleri aşağıda belirtilmiştir:
* Grafiksel bir dijital devre simulasyonu tasarım ve yapımı
* CISC işlemci devresi tasarımı ve simulasyonu
* RISC işlemci devresi tasarım ve simulasyonu
* Simulasyon kullanarak bu iki mimarinin kıyaslanması
A.3 Arkaplan İşleri İçin Plan
Bu proje için gereken arkaplan işleri iki kısımdan oluşuyor. İlk olarak mevcut CISC ve RISC
mimarilerinin örnek devrelerini tasarlayabileceğimiz şekilde araştırılması. İkinci kısım olarak son
Java versiyonu 1.1.4'ü öğrenmek ve projeye uygunluğunu değerlendirmek. Bunların ikisi de tasarım
başlangıç süresinden önce örneğin 1997 yaz tatili sırasında tamamlanmalı.
38
A.4 İş Planı ve Dönüm Noktaları
Aşağıdaki tabloda iş planının özeti ve son teslim tarihleri bulunuyor. Bu işlemlerin çoğu
paralel yürütülebilir (örneğin iki işlemci devresinin tasarımı).
Dijital simulasyon tasarımı
0. hafta Michaelmas
GUI kodu
2. hafta Michaelmas
Kod yükleme, kaydetme ve bileşenlerin yerleştirilmesi 4. hafta Michaelmas
Kod devre simulasyonu
6. hafta Michaelmas
Basit devrelerle test simulasyonu
8. hafta Michaelmas
CISC işlemcinin tasarım ve testi
0. hafta Hilary
RISC işlemcinin tasarım ve testi
4. hafta Hilary
CISC ve RISC karşılaştırması
8. hafta Hilary
0. hafta Trinity
A.5 Danışman İle İletişim
Proje hedefleri net bir şekilde tanımlandığına ve izleyeceğim yol bana bırakıldığına göre
okul süresince iki haftada bir kez supervisörümle görüşmem yeterli olacaktir. Bu nedenle Dr
Sanders ile 27/6/97, 22/10/97, 7/11/97 ve 21/11/97 günlerinde görüştüm. Bu görüşmeler genellikle
sürecin işleyişinin kontrolü ve gelecekte ilerleyeceğimiz yolla ilgiliydi.
A.6 progress to date
Sürecin işleyişi yukarda da belirtilen planlarda olduğu gibi gerçeklesti. Yaz tatili süresince
iki mimariyi de inceledim ve Java'nın projeye uygunluğuna karar vermek için küçük bir prototip
geliştirdim. Benim istediğim kadar ayrıntılı olmasa da simulasyon tasarımı oluşturdu.
İş son günlere kadar devam etti. Şu anda 6. hafta Michaelmas term ve program basit 2-bitlik
ALU simulasyon yapabiliyor. Proje ilerledikçe simulasyon fonksiyonelliği de artıyor, örneğin
simulasyon sırasında paketlerin içine bakabilme ve devreye eklenen probelar sayesinde çıkış izlerini
oluşturma gibi. Önemli ölçüde zaman da kolay kullanımlı ve sade bir grafiksel arayüz birimi için
harcandı.
Küçük bir problem Sun tarafından Java Found Class (swing) beta sürümünün açıklanması
oldu. Her ne kadar bazı alanlarda kullanışlı olduysa da bu yeni class'ı kodun içine yerleştirmek için
bazı yerlerin yeniden yazılması gerekti ve başarılı olmasına rağmen beta sürüm olması yüzünden
pekçok bug içermesi ve kaynak azlığı sorun yarattı. Umuyorum ki tam sürüm proje tamamlanmadan
bitirilir.
39

Benzer belgeler