EDA Playground'da Dene

Events (Olaylar)

Gün 4: Süreçler Arası İletişim (IPC) | Olay tetikleme (->), bekleme (@, wait) ve senkronizasyon

Bu derste SystemVerilog'un event veri tipini öğreneceksiniz. Olaylar (events), paralel süreçleri birbirine veri vermeden ya da el sıkışma (handshake) yaparak senkronize etmenin en hafif ve en temel yoludur.

Event (Olay) Nedir?

Bir event, SystemVerilog'da herhangi bir veri taşımayan, yalnızca "bir şey oldu" sinyalini bir süreçten diğerine ileten özel bir tiptir. Üç temel işlemle kullanılır:

  • Tanımlama: event ad; ile bir olay nesnesi oluşturulur.
  • Tetikleme (trigger): -> ad; ifadesi olayı tetikler ve o an o olayı bekleyen tüm süreçleri uyandırır.
  • Bekleme: @(ad) veya wait(ad.triggered) ile bir süreç, olay tetiklenene kadar bloklanır.

Neden Önemli ve Nerede Kullanılır?

  • Senkronizasyon: "Reset bitmeden hiçbir bileşen çalışmaya başlamasın" gibi kuralları kolayca kurarsınız.
  • El sıkışma (handshake): Üretici (producer) "veri hazır" der, tüketici (consumer) işleyip "onay" geri gönderir. Bu çift yönlü senkronizasyon olaylarla zarif biçimde yazılır.
  • Faz kontrolü: Bir işin tüm aşamalarının bittiğini haber vermek için phase_complete gibi olaylar kullanılır.

@(olay) kenar tetiklemeli (edge-sensitive) çalışır: yani sürecin olayı yakalayabilmesi için, beklemeye olay tetiklenmeden önce geçmiş olması gerekir. wait(olay.triggered) ise olayın o zaman adımında tetiklenip tetiklenmediğini de görür; bu ince fark bir sonraki derste detaylıca incelenir.

Kaynak Kod

// =============================================================================
// GUN 4 - Konu 3: Event'ler - Olay Tetikleme ve Bekleme
// =============================================================================

module events;
  // Event tanimla
  event data_ready;
  event ack_received;
  event reset_done;
  event phase_complete;

  int shared_data;

  // --- Uretici (Producer) ---
  initial begin : producer
    $display("=== Events (Olay Tetikleme) ===\n");

    // Reset bekle
    @(reset_done);
    $display("  [%0t] Uretici: Reset tamamlandi, calismaya basliyor", $time);

    repeat (5) begin
      #10;
      shared_data = $urandom_range(1, 100);
      $display("  [%0t] Uretici: Veri uretildi = %0d", $time, shared_data);
      -> data_ready;  // Olayi tetikle

      @(ack_received);  // Tuketici onayini bekle
      $display("  [%0t] Uretici: Onay alindi", $time);
    end

    $display("\n  [%0t] Uretici: Tum veriler gonderildi", $time);
    -> phase_complete;
  end

  // --- Tuketici (Consumer) ---
  initial begin : consumer
    @(reset_done);
    $display("  [%0t] Tuketici: Reset tamamlandi", $time);

    forever begin
      @(data_ready);  // Veri hazir olayini bekle
      $display("  [%0t] Tuketici: Veri alindi = %0d", $time, shared_data);
      #5;  // Isleme suresi
      -> ack_received;  // Onay gonder
    end
  end

  // --- Reset sureci ---
  initial begin : reset_gen
    $display("  [%0t] Reset basladi...", $time);
    #20;
    $display("  [%0t] Reset tamamlandi!", $time);
    -> reset_done;
  end

  // --- wait() ile event bekleme ---
  initial begin
    wait(phase_complete.triggered);
    $display("\n  [%0t] Phase tamamlandi (wait ile algilandi)", $time);
  end

  // --- Triggered ozelligi ---
  initial begin
    #200;  // Zaman asimi
    $display("\n=== Events Sonu ===");
    $finish;
  end
endmodule

Kodun Açıklaması

  • Modülün başında dört olay tanımlanır: data_ready, ack_received, reset_done ve phase_complete. shared_data ise üretici ile tüketici arasında paylaşılan veridir.
  • reset_gen bloğu: 20ns boyunca reset uygular, ardından -> reset_done; ile reset bitişini duyurur. Hem producer hem consumer blokları başında @(reset_done) ile beklediği için, ikisi de ancak reset bittikten sonra çalışmaya başlar.
  • producer bloğu: Bir döngü içinde 5 kez veri üretir. Her seferinde shared_data'yı $urandom_range(1, 100) ile rastgele doldurur, -> data_ready; ile "veri hazır" der ve sonra @(ack_received) ile tüketicinin onayını bekler. Bu, klasik bir el sıkışma döngüsüdür.
  • consumer bloğu: forever döngüsü içinde @(data_ready) ile veri beklenir, shared_data okunur, #5 işleme süresi geçer ve -> ack_received; ile onay geri gönderilir. Üretici ve tüketici bu sayede birbirini kilitlemeden, sırayla ilerler.
  • wait(phase_complete.triggered): Ayrı bir initial blok, üreticinin tüm verileri gönderip tetiklediği phase_complete olayını bekler ve fazın bittiğini bildirir.
  • Son initial blok ise #200 zaman aşımıyla simülasyonu $finish ile sonlandırır.

Önemli Noktalar

  • @(olay) kenar tetiklemelidir: bekleyen süreç, olay tetiklenmeden önce beklemeye geçmiş olmalıdır. Aksi halde tetiklemeyi kaçırır ve sonsuza kadar bekleyebilir (race condition).
  • Üretici-tüketici el sıkışmasında data_ready ve ack_received olaylarının sırası kritiktir; her iki taraf da karşılıklı beklediği için döngü kilitlenmeden ilerler.
  • Birden çok süreç aynı reset olayını (reset_done) beklediğinde, -> reset_done; ile yapılan tek bir tetikleme hepsini aynı anda uyandırır.
  • wait(olay.triggered), olayın o zaman adımında tetiklenip tetiklenmediğini de algılar; bu yüzden phase_complete gibi tek seferlik bayraklarda @ yerine genellikle daha güvenlidir.
  • Olaylar veri taşımaz; aktarılacak gerçek veri için (burada shared_data gibi) ayrı bir paylaşılan değişken ya da mailbox kullanılır.