EDA Playground'da Dene

Kuyruklar (Queues)

Gün 1: SystemVerilog'a Giriş ve Veri Tipleri | Kuyruk yapısı ve metodları: push, pop, find, sort

Bu derste SystemVerilog kuyruklarını (queue) öğreniyoruz: iki ucundan da büyüyüp küçülebilen, FIFO/LIFO davranışını destekleyen ve doğrulamada sıkça kullanılan esnek bir veri yapısı.

Kuyruk Nedir?

Kuyruk (queue), $ sembolüyle tanımlanan, çalışma zamanında boyutu değişebilen sıralı bir koleksiyondur. Dinamik diziye benzer ama her iki uçtan da hızlı ekleme/çıkarma yapabilmesiyle ayrılır. Bu yüzden testbench'lerde scoreboard, FIFO modeli ve geçici veri tamponları için idealdir.

  • int q_int [$]; → sınırsız (unbounded) kuyruk
  • int bounded_q [$:9]; → en fazla 10 elemanlı sınırlı (bounded) kuyruk
  • Kuyruk elemanları struct gibi karmaşık tipler de olabilir (packet_t q_pkt [$];)

Temel Metodlar

  • Ekleme: push_back() (sona), push_front() (başa), insert(idx, val) (belirli indekse)
  • Çıkarma: pop_front() (baştan), pop_back() (sondan), delete(idx) (indeksten sil)
  • Erişim: q[0] ilk, q[$] son eleman, q[a:b] dilimleme (slicing)
  • Sorgu/düzen: size(), sort(), rsort(), reverse(), shuffle()

Arama: find ve with

Kuyruklar (ve diziler) güçlü bir with yan tümcesiyle filtreleme sunar. find with (item == 30) koşulu sağlayan elemanları, find_index with (...) ise bu elemanların indekslerini döndürür. Burada item, her elemanı temsil eden örtük (implicit) değişkendir. FIFO davranışı genellikle push_back + pop_front ikilisiyle modellenir.

Kaynak Kod

// =============================================================================
// GUN 1 - Konu 6: Kuyruklar (Queues) ve Metodlari
// =============================================================================

module kuyruklar;

  // Kuyruk tanimlama: $ sembolu ile
  int q_int [$];                           // Bos kuyruk
  string q_str [$];                        // String kuyruk
  int bounded_q [$:9];                     // Maksimum 10 elemanli sinirli kuyruk

  typedef struct {
    int    id;
    string name;
    int    data;
  } packet_t;
  
  typedef struct {
    int    id;
    int    data;
    int    cksum;
  } packet_w_cksum;

  packet_t q_pkt [$];                     // Struct kuyruk
  packet_w_cksum q_pkt_cksum [$];

  initial begin
    $display("=== SystemVerilog Kuyruklar (Queues) ===\n");

    // --- Temel Islemler ---
    $display("--- Temel Kuyruk Islemleri ---");

    // push_back: Sona ekle
    q_int.push_back(10);
    q_int.push_back(20);
    q_int.push_back(30);
    q_int.push_back(40);
    q_int.push_back(50);
    $display("  push_back sonrasi: %p", q_int);
    $display("  Boyut = %0d", q_int.size());

    // push_front: Basa ekle
    q_int.push_front(5);
    $display("  push_front(5) sonrasi: %p", q_int);

    // pop_front: Bastan cikar
    begin
      int val;
      val = q_int.pop_front();
      $display("  pop_front() = %0d, Kuyruk: %p", val, q_int);
    end

    // pop_back: Sondan cikar
    begin
      int val;
      val = q_int.pop_back();
      $display("  pop_back()  = %0d, Kuyruk: %p", val, q_int);
    end

    // --- Ekleme ve Silme ---
    $display("\n--- insert ve delete ---");
    q_int.insert(2, 25);  // Indeks 2'ye 25 ekle
    $display("  insert(2, 25): %p", q_int);

    q_int.delete(0);      // Indeks 0'i sil
    $display("  delete(0):     %p", q_int);

    // --- Erisim ---
    $display("\n--- Eleman Erisimi ---");
    $display("  Ilk eleman    q[0]   = %0d", q_int[0]);
    $display("  Son eleman    q[$]   = %0d", q_int[$]);
    $display("  Dilimleme     q[1:2] = %p", q_int[1:2]);

    // --- Arama Metodlari ---
    $display("\n--- Arama Metodlari ---");
    q_int = '{15, 30, 45, 30, 60, 15};
    $display("  Kuyruk = %p", q_int);
    
    begin
      int found [$];
      found = q_int.find with (item == 30);
      $display("  find(==30)        = %p", found);
      
      found = q_int.find_index with (item == 30);
      $display("  find_index(==30)  = %p", found);

      found = q_int.find with (item > 40);
      $display("  find(>40)         = %p", found);

      found = q_int.min();
      $display("  min               = %p", found);

      found = q_int.max();
      $display("  max               = %p", found);

      found = q_int.unique();
      $display("  unique            = %p", found);
    end

    // --- Siralama ---
    $display("\n--- Siralama ---");
    q_int.sort();
    $display("  sort()    = %p", q_int);
    q_int.rsort();
    $display("  rsort()   = %p", q_int);
    q_int.reverse();
    $display("  reverse() = %p", q_int);
    q_int.shuffle();
    $display("  shuffle() = %p", q_int);

    // --- Struct Kuyruk ---
    $display("\n--- Struct Kuyruk ---");
    q_pkt.push_back('{id: 1, name: "READ",  data: 'hAA});
    q_pkt.push_back('{id: 2, name: "WRITE", data: 'hBB});
    q_pkt.push_back('{id: 3, name: "READ",  data: 'hCC});
    
    foreach (q_pkt[i])
      $display("  Paket[%0d]: id=%0d, name=%s, data=0x%02h",
               i, q_pkt[i].id, q_pkt[i].name, q_pkt[i].data);
    
    // Struct'ta default kullanımı:
    $display("\n--- Default ile atama ---");
    q_pkt_cksum.push_back('{id:1, default: 0});
    q_pkt_cksum.push_back('{id:2, data: 123, default: 0});
    foreach (q_pkt_cksum[i])
      $display("  Paket[%0d]: id=%0d, data=%0d, cksum=%0d",
               i, q_pkt_cksum[i].id, q_pkt_cksum[i].data, q_pkt_cksum[i].cksum);

    // FIFO benzeri kullanim
    $display("\n  FIFO Kullanimi:");
    begin
      packet_t p;
      while (q_pkt.size() > 0) begin
        p = q_pkt.pop_front();
        $display("  Isleniyor: id=%0d, %s (0x%02h)", p.id, p.name, p.data);
      end
    end

    $display("\n=== Kuyruklar Sonu ===");
    $finish;
  end

endmodule

Kodun Açıklaması

  • int q_int [$]; sınırsız bir kuyruktur. Ardışık q_int.push_back(...) çağrılarıyla sona elemanlar eklenir; q_int.push_front(5); ise başa ekler. q_int.size() anlık eleman sayısını verir.
  • q_int.pop_front() baştan, q_int.pop_back() sondan eleman çıkarıp döndürür. Çıkarılan değer örnekte yerel val değişkenine alınır.
  • q_int.insert(2, 25); indeks 2'ye 25 ekler; q_int.delete(0); indeks 0'daki elemanı siler.
  • Erişimde q_int[0] ilk elemanı, q_int[$] son elemanı, q_int[1:2] ise bir dilimi (alt kuyruk) verir.
  • Arama bölümünde kuyruk '{15, 30, 45, 30, 60, 15} ile sıfırlanır. q_int.find with (item == 30) değeri 30 olan elemanları, find_index with (item == 30) bunların indekslerini döndürür. find with (item > 40) koşullu filtrelemeyi gösterir. min(), max(), unique() ise tek elemanlı/çok elemanlı sonuç kuyrukları döndürür; bu yüzden hepsi found adlı kuyruğa atanır.
  • Sıralama bölümünde sort() artan, rsort() azalan sırada sıralar; reverse() mevcut sırayı ters çevirir; shuffle() rastgele karıştırır.
  • q_pkt bir struct kuyruğudur. q_pkt.push_back('{id: 1, name: "READ", data: 'hAA}); gibi struct literal'lar eklenir ve foreach ile alanları (id, name, data) yazdırılır.
  • q_pkt_cksum.push_back('{id:1, default: 0}); satırı struct literal'da default anahtarını gösterir: açıkça verilmeyen tüm alanlar (data, cksum) 0 ile doldurulur. İkinci örnekte yalnızca data: 123 verilir, kalanlar yine default: 0 olur.
  • Sonda FIFO kullanımı: while (q_pkt.size() > 0) döngüsünde q_pkt.pop_front() ile paketler ekleniş sırasıyla işlenir.

Önemli Noktalar

  • Kuyruklar her iki uçtan da verimli ekleme/çıkarma sağlar; FIFO için push_back + pop_front, LIFO (yığın) için push_back + pop_back kullanın.
  • find, find_index, min, max, unique gibi metodlar yeni bir kuyruk döndürür; bu yüzden sonucu daima bir kuyruğa atayın (örnekteki found gibi).
  • with yan tümcesindeki item örtük değişkendir; karmaşık elemanlarda item.alan_adi (örneğin item.pkt_type) şeklinde alanlara erişebilirsiniz.
  • Boş bir kuyrukta pop_front/pop_back çağırmak tanımsız davranışa yol açar; çıkarmadan önce size() > 0 kontrolü yapın.
  • struct literal'larında default anahtarı, belirtilmeyen alanları tek seferde başlatmanın temiz bir yoludur ve unutulan alan hatalarını azaltır.
  • Sınırlı kuyruk ([$:N]) kapasiteyi belgelemek ve sınırlamak için kullanışlıdır; tasarımdaki gerçek FIFO derinliğini modellemek için idealdir.