VHDL ile 8 Bit CPU Tasarlamak

VHDL İle 8 Bit CPU Tasarlamak

VHDL ile 8-bit CPU tasarlamak, bilgisayarın saatin her bir yükselen kenarında (rising edge) veriyi bellekten nasıl çektiğini, nasıl işlediğini ve yürüttüğünü moleküler düzeyde kavramak için eşsiz bir eğitim sürecidir.

Bilgisayar mimarisi ve sayısal tasarım (digital design) dünyasının en büyüleyici projelerinden biri, bir mikroişlemcinin (CPU) o gizemli “kara kutusunu” açıp en temel mantık kapılarından başlayarak onu VHDL (VHSIC Hardware Description Language) donanım tanımlama dili ile sıfırdan inşa etmektir.

Bu proje çalışması, sadece nostaljik bir 8-bit mikroişlemci simülasyonu değildir. Bugün modern bilgisayarlarımızda çalışan çok çekirdekli Gigahertz seviyesindeki devasa işlemcilerin altında yatan temel mimari prensipler (veri yolu akışı, kontrol mantığı, bellek erişimi ve ALU), hala bu basit 8-bit yapı taşları üzerinde yükselmektedir.

Mimari Karar: Harvard vs Von Neumann

Tasarım aşamasına geçmeden önce karar verilmesi gereken ilk konu bellek mimarisidir. Von Neumann mimarisinde komutlar (program) ve veriler (data) tek bir fiziksel bellekte tutulur ve aynı sistem veri yolunu (bus) paylaşır. Bu durum, veri transferi yapılırken aynı anda yeni bir komutun çekilememesine yol açar (Von Neumann Bottleneck / Darboğazı).

Buna karşın Harvard mimarisi, komut belleği (Instruction Memory) ve veri belleği (Data Memory) için tamamen bağımsız fiziksel yollar ve otobüsler kullanır. Bu sayede, saat darbesiyle eş zamanlı olarak hem komut çekilebilir hem de veri RAM’e yazılabilir. 8-bit tasarımlarda basitlik ve hız avantajı nedeniyle genellikle Harvard mimarisi tercih edilir.

İşlemcinin Donanımsal Yapı Taşları

Bir mikroişlemci tasarlamak, her birimin görevinin matematiksel kesinlikle tanımlandığı entegre bir şehir planlaması yapmaya benzer:

  • ALU (Arithmetic Logic Unit): İşlemcinin kalbidir. Girdi olarak verilen iki adet 8-bitlik veri üzerinde toplama (ADD), çıkarma (SUB), mantıksal VE (AND), VEYA (OR) ve XOR gibi işlemleri gerçekleştirir ve sonuçla birlikte durum flaglerini (Sıfır – Zero, Taşıma – Carry, Negatif – Negative) üretir.
  • Kayıtçılar ve Kayıt Dosyası (Register File): RAM bellek erişimi saat bazında yavaş olduğu için, ALU’nun anlık işleyeceği veriler ultra hızlı flip-flop tabanlı geçici hücrelerde (R0, R1, R2, Accumulator) saklanır.
  • Program Sayacı (PC – Program Counter): Bir sonraki adımda bellekten çekilecek komutun adresini tutan ve her çevrimde (cycle) otomatik olarak bir artan (PC = PC + 1) veya dallanma (Branch/Jump) durumunda hedeflenen adrese kilitlenen işaretçi birimidir.
  • Kontrol Ünitesi (Control Unit): Sistemdeki en karmaşık birimdir. Hafızadan gelen ikili (binary) komut kodunu çözer ve ALU, RAM ve Kayıtçılar arasındaki multiplexer ve etkinleştirme (enable) hatlarına hangi verinin ne zaman geçeceğini söyleyen bir orkestra şefidir.
VHDL ile 8 Bit CPU Tasarlamak
VHDL ile 8 Bit CPU Tasarlamak

VHDL Tasarım Adımları ve Kodlama Metodolojisi

Sayısal tasarımda kod yazarken, yazdığınız kodun bir C programı gibi sırayla işletilmediğini, aslında fiziksel VE / VEYA / flip-flop donanım kapılarını bağladığınızı (Hardware Synthesis) asla unutmamalısınız.

1. Adım: Komut Setini (ISA – Instruction Set Architecture) Belirleyin

Her şey CPU’nun anlayacağı komut formatını (Machine Code) tanımlamakla başlar. Örneğin, 8-bitlik bir komutun ilk 4 bitini işlem kodu (OpCode), son 4 bitini ise hedef kayıtçı adresi veya doğrudan veri (immediate value) olarak atayabiliriz:

  • 0001 (ADD): ALU üzerinde toplama işlemi tetikler.
  • 0010 (SUB): ALU üzerinde çıkarma işlemi tetikler.
  • 0100 (LD): Bellekten (RAM) kayıtçıya veri yükler.
  • 1000 (JMP): Program sayacına yeni adres yükleyerek dallanma gerçekleştirir.

2. Adım: ALU ve Kombinasyonel Mantık Tasarımı

Aritmetik Mantık Birimi, kombinasyonel (combinational) bir devredir. Yani çıktısı, girdilerin o anki durumuna bağlıdır ve saat darbesine (Clock) ihtiyaç duymaz. VHDL’de bir ALU tasarımı genellikle şu şekilde yapılandırılır:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity alu_8bit is
    Port ( 
        A      : in  STD_LOGIC_VECTOR(7 downto 0);
        B      : in  STD_LOGIC_VECTOR(7 downto 0);
        Sel    : in  STD_LOGIC_VECTOR(2 downto 0);
        Result : out STD_LOGIC_VECTOR(7 downto 0);
        Zero   : out STD_LOGIC
    );
end alu_8bit;

architecture Behavioral of alu_8bit is
    signal temp_res : unsigned(7 downto 0);
begin
    process(A, B, Sel)
    begin
        case Sel is
            when "000" => temp_res <= unsigned(A) + unsigned(B); -- ADD
            when "001" => temp_res <= unsigned(A) - unsigned(B); -- SUB
            when "010" => temp_res <= unsigned(A) and unsigned(B); -- AND
            when "011" => temp_res <= unsigned(A) or unsigned(B);  -- OR
            when "100" => temp_res <= unsigned(A) xor unsigned(B); -- XOR
            when others => temp_res <= (others => '0');
        end case;
    end process;
    
    Result <= std_logic_vector(temp_res);
    Zero <= '1' when (temp_res = 0) else '0';
end Behavioral;

Önemli Hata: İstenmeyen Latch (Unintentional Latch) Oluşumu

⚠️ KRİTİK VHDL UYARISI: LATCH TEHLİKESİ!
Kombinasyonel bir process bloğu yazarken (örneğin yukarıdaki ALU veya kontrol sinyalleri çözücü devresi), eğer tüm olası durumlara değer atamazsanız (örneğin if ifadesinin else dalını yazmayı unutursanız veya case yapısında when others kısmını boş bırakırsanız), sentezleyici (compiler) eski değeri korumak isteyeceğinizi varsayar.

Bunu sağlamak için sentezleyici, devrenize fiziksel olarak latch yerleştirir. Latch yapıları, saat darbesinden bağımsız seviye tetiklemeli geçici hafıza elemanlarıdır ve FPGA tasarımlarında beklenmedik zamanlama (timing) hatalarına, metastabiliteye ve kararsız çalışmalara sebep olur. Bu nedenle kombinasyonel process bloklarında her zaman tüm sinyallere varsayılan bir başlangıç değeri atayın veya when others => / else dallarını eksiksiz doldurun.

3. Adım: Kontrol Ünitesi ve İki Süreçli FSM Deseni

Kontrol birimi, işlemcinin klasik Fetch (Komut Getir), Decode (Komut Çöz), Execute (Çalıştır) adımlarını yöneten bir Sonlu Durum Makinesidir (FSM – Finite State Machine). En güvenli ve profesyonel FSM tasarımı, İki Süreçli (Two-Process FSM) yapı kullanılarak yazılır. Birinci süreç tamamen senkronize olarak saat kenarında durum geçişini (state transition) yönetirken, ikinci süreç ise tamamen kombinasyonel olarak sonraki durumu (next state) ve kontrol sinyalleri çıkışlarını hesaplar:

type state_type is (STATE_FETCH, STATE_DECODE, STATE_EXECUTE);
signal current_state, next_state : state_type;

-- 1. Süreç: Ardışıl (Sequential) Durum Güncelleme
process(Clk, Reset)
begin
    if Reset = '1' then
        current_state <= STATE_FETCH;
    elsif rising_edge(Clk) then
        current_state <= next_state;
    end if;
end process;

-- 2. Süreç: Kombinasyonel (Combinational) Çıkış ve Durum Mantığı
process(current_state, OpCode)
begin
    -- Sentez sırasında latch oluşmasını engellemek için varsayılan çıkış tanımları
    alu_sel <= "000";
    reg_write_enable <= '0';
    
    case current_state is
        when STATE_FETCH =>
            -- Komutu hafızadan çekme sinyallerini aktif et
            next_state <= STATE_DECODE;
            
        when STATE_DECODE =>
            -- OpCode'a göre sonraki adımı belirle
            next_state <= STATE_EXECUTE;
            
        when STATE_EXECUTE =>
            if OpCode = "0001" then -- ADD işlemi
                alu_sel <= "000";
                reg_write_enable <= '1';
            end if;
            next_state <= STATE_FETCH; -- Döngüyü başa sar
            
        when others =>
            next_state <= STATE_FETCH;
    end case;
end process;

4. Adım: Simülasyon, Testbench ve Sentez (Verification)

Yazılan VHDL kodunun doğruluğu, doğrudan sentezlenip FPGA kartına yüklenmeden önce simülasyon programları yardımıyla test edilmelidir. Intel FPGA / Altera FPGA ekosisteminde yer alan ModelSim veya Xilinx Vivado simülatörleri kullanılarak, tasarlanan işlemcinin her saat vuruşundaki register ve veri yolu (datapath) dalga formları milisaniye hassasiyetinde incelenir.

Bu test süreci için özel olarak yazılan Testbench dosyaları, işlemciye sanal reset ve clock darbeleri gönderir, RAM bellek içeriğine örnek program yükler ve ALU çıktılarının doğruluk tablosunu otomatik olarak kontrol eder. Simülasyon sürecinde hata vermeyen kararlı kod, sentezlenip (synthesized) fiziksel bir FPGA kartı (örn. Cyclone IV veya Artix-7) üzerine kapılanarak fiziksel donanım dünyasında çalıştırılır.

VHDL Tasarımcıları İçin Altın Kurallar

  • Tek Tip Reset Politikası: Tasarım genelinde senkron ve asenkron resetleri birbirine karıştırmayın. Gözlemlenmesi zor kararsız durumları önlemek için sistemin tamamında asenkron aktif-yüksek (active-high) veya aktif-düşük tek tip reset mimarisi benimseyin.
  • Senkron Saat Sınırları: Farklı saat sinyalleri arasında veri taşırken metastabilite sorununu engellemek için çift aşamalı senkronizasyon flip-flop’ları kullanın.
  • Modüler Geliştirme: İşlemciyi devasa tek bir kod dosyası olarak yazmak yerine, ALU, PC, RAM ve Kontrol Ünitesini ayrı VHDL dosyaları (entity’ler) olarak tasarlayıp üst seviye bir yapısal (Structural) şemada (`top_level.vhd`) birleştirin.

VHDL kodlama standartları, FPGA kartlarında sentezlenebilir (synthesizable) kod kalıpları ve ileri seviye testbench yazma teknikleri hakkında temel kaynak niteliğinde olan NANDLAND VHDL Başlangıç Kılavuzu ve Altera platformları için simülasyon adımlarını içeren Intel Quartus Prime ve ModelSim Simülasyon Kılavuzunu inceleyerek tasarımlarınızı profesyonel standartlara ulaştırabilirsiniz.

Yorum yapma özelliği, forum tarafından gelen istek sebebiyle kapatılmıştır. Lütfen tartışmalar ve sorularınız için topluluk forumumuza katılın.