EDA Playground'da Dene

Lab 1: Veri Paketleri

Gün 1: SystemVerilog'a Giriş ve Veri Tipleri | Ağ paketi oluşturma ve dizi metodlarını test etme

Aşağıdaki kod, egzersizin tamamlanmış halidir. Önce EDAPlayground'da kendinizi deneyin. Sonrasında buradakiyle karşılaştırabilirsiniz. Başarılar!

Bu laboratuvarda Gün 1 boyunca öğrendiğimiz tüm parçaları tek bir uygulamada birleştiriyoruz: enum, struct, kuyruklar, fonksiyonlar ve dizi metodları ile gerçekçi bir ağ paketi (network packet) modeli kuracağız.

Lab'ın Amacı

Bu egzersiz, ayrı ayrı öğrenilen kavramların gerçek bir doğrulama senaryosunda nasıl bir araya geldiğini göstermeyi hedefler. Adım adım:

  • Bir paket tipini enum (pkt_type_e) ve struct (network_packet_t) ile modelleyeceğiz.
  • Paketleri yeniden kullanılabilir bir fonksiyon (create_packet) ile üretip bir kuyruğa ekleyeceğiz.
  • find with filtreleriyle paketleri tipe, geçerliliğe, boyuta ve hedef adrese göre süzeceğiz.
  • Dizi metodlarıyla (sum, min, max, sort) istatistik çıkaracağız.
  • Kuyruğu FIFO mantığıyla işleyerek tüketeceğiz.

Kullanılan Kavramlar

  • enum + struct: Paket tipini ve alanlarını anlamlı isimlerle gruplamak.
  • Kuyruk içinde kuyruk: network_packet_t içindeki byte payload [$] alanı, struct'ın içinde dinamik bir veri tutar.
  • Fonksiyonlar: create_packet bir struct döndürürken, print_packet void döndürerek yalnızca çıktı üretir.
  • find with ve item: Karmaşık elemanlarda item.pkt_type, item.valid, item.length, item.dst_addr gibi alanlar üzerinden filtreleme.

Kaynak Kod

// =============================================================================
// GUN 1 - Lab 1: Veri Paketleri Olusturma ve Dizi Metodlarini Test Etme
// =============================================================================
// Bu laboratuvar calismasinda:
// - Cesitli veri tipleri kullanarak bir ag paketi modeli olusturulacak
// - Paketler dizilere ve kuyruklara eklenecek
// - Dizi metodlari ile filtreleme, siralama yapilacak
// =============================================================================

module lab1_veri_paketleri;

  // Paket tipi enum
  typedef enum logic [1:0] {
    PKT_DATA   = 2'b00,
    PKT_ACK    = 2'b01,
    PKT_NACK   = 2'b10,
    PKT_CTRL   = 2'b11
  } pkt_type_e;

  // Paket yapisi
  typedef struct {
    int          id;
    pkt_type_e   pkt_type;
    logic [15:0] src_addr;
    logic [15:0] dst_addr;
    byte         payload [$];
    int          length;
    bit          valid;
  } network_packet_t;

  // Paket kuyruklari
  network_packet_t pkt_queue [$];
  network_packet_t filtered  [$];

  // Paket olusturma fonksiyonu
  function network_packet_t create_packet(
    int id, pkt_type_e ptype, 
    logic [15:0] src, logic [15:0] dst,
    int payload_len, bit valid_flag
  );
    network_packet_t pkt;
    pkt.id       = id;
    pkt.pkt_type = ptype;
    pkt.src_addr = src;
    pkt.dst_addr = dst;
    pkt.length   = payload_len;
    pkt.valid    = valid_flag;
    
    // Payload olustur
    for (int i = 0; i < payload_len; i++)
      pkt.payload.push_back(byte'(i + 'hA0));
    
    return pkt;
  endfunction

  // Paket yazdirma fonksiyonu
  function void print_packet(network_packet_t pkt);
    $display("  Paket #%0d | Tip: %-4s | Src: 0x%04h | Dst: 0x%04h | Len: %0d | Gecerli: %0b",
             pkt.id, pkt.pkt_type.name(), pkt.src_addr, pkt.dst_addr, pkt.length, pkt.valid);
  endfunction

  initial begin
    $display("============================================================");
    $display("  LAB 1: Ag Paketi Olusturma ve Dizi Metodlari Testi");
    $display("============================================================\n");

    // --- Paketleri olustur ve kuyruga ekle ---
    $display("--- 1. Paket Olusturma ---");
    pkt_queue.push_back(create_packet(1, PKT_DATA, 16'h0001, 16'h0002, 64, 1));
    pkt_queue.push_back(create_packet(2, PKT_ACK,  16'h0002, 16'h0001, 0,  1));
    pkt_queue.push_back(create_packet(3, PKT_DATA, 16'h0003, 16'h0002, 128,1));
    pkt_queue.push_back(create_packet(4, PKT_NACK, 16'h0002, 16'h0003, 0,  1));
    pkt_queue.push_back(create_packet(5, PKT_DATA, 16'h0001, 16'h0004, 32, 0)); // Gecersiz
    pkt_queue.push_back(create_packet(6, PKT_CTRL, 16'h0001, 16'hFFFF, 8,  1));
    pkt_queue.push_back(create_packet(7, PKT_DATA, 16'h0005, 16'h0002, 256,1));
    pkt_queue.push_back(create_packet(8, PKT_DATA, 16'h0003, 16'h0001, 16, 0)); // Gecersiz

    $display("  Toplam %0d paket olusturuldu.\n", pkt_queue.size());
    foreach (pkt_queue[i]) print_packet(pkt_queue[i]);

    // --- Filtreleme: Sadece DATA paketleri ---
    $display("\n--- 2. Filtreleme: Sadece DATA Paketleri ---");
    filtered = pkt_queue.find with (item.pkt_type == PKT_DATA);
    $display("  DATA paketi sayisi: %0d", filtered.size());
    foreach (filtered[i]) print_packet(filtered[i]);

    // --- Filtreleme: Gecerli paketler ---
    $display("\n--- 3. Filtreleme: Gecerli Paketler ---");
    filtered = pkt_queue.find with (item.valid == 1);
    $display("  Gecerli paket sayisi: %0d", filtered.size());
    foreach (filtered[i]) print_packet(filtered[i]);

    // --- Filtreleme: Buyuk paketler (len > 50) ---
    $display("\n--- 4. Filtreleme: Payload > 50 Byte ---");
    filtered = pkt_queue.find with (item.length > 50);
    $display("  Buyuk paket sayisi: %0d", filtered.size());
    foreach (filtered[i]) print_packet(filtered[i]);

    // --- Filtreleme: Belirli hedef adres ---
    $display("\n--- 5. Filtreleme: Hedef = 0x0002 ---");
    filtered = pkt_queue.find with (item.dst_addr == 16'h0002);
    $display("  Eslesen paket sayisi: %0d", filtered.size());
    foreach (filtered[i]) print_packet(filtered[i]);

    // --- Istatistikler ---
    $display("\n--- 6. Istatistikler ---");
    begin
      int lengths [$];
      foreach (pkt_queue[i]) lengths.push_back(pkt_queue[i].length);
      $display("  Toplam payload  = %0d byte", lengths.sum());
      $display("  Min payload     = %0d byte", lengths.min());
      $display("  Max payload     = %0d byte", lengths.max());
      
      lengths.sort();
      $display("  Sirali payload  = %p", lengths);
    end

    // --- FIFO Isleme ---
    $display("\n--- 7. FIFO Isleme ---");
    $display("  Kuyruk boyutu = %0d", pkt_queue.size());
    while (pkt_queue.size() > 0) begin
      network_packet_t p = pkt_queue.pop_front();
      $display("  Islendi: Paket #%0d (%s)", p.id, p.pkt_type.name());
    end
    $display("  Kuyruk boyutu = %0d (Tumu islendi)", pkt_queue.size());

    $display("\n============================================================");
    $display("  LAB 1 TAMAMLANDI");
    $display("============================================================");
    $finish;
  end

endmodule

Kodun Açıklaması

  • pkt_type_e enum'u dört paket tipini (PKT_DATA, PKT_ACK, PKT_NACK, PKT_CTRL) logic [1:0] tabanında tanımlar.
  • network_packet_t struct'ı bir paketin tüm alanlarını taşır: id, pkt_type, src_addr, dst_addr, dinamik byte payload [$], length ve valid. Burada bir struct'ın içinde kuyruk barındırabildiğini görüyoruz.
  • pkt_queue ve filtered, network_packet_t tipinde iki struct kuyruğudur.
  • create_packet(...) fonksiyonu bir network_packet_t döndürür. Alanları parametrelerden doldurur ve for (int i = 0; i < payload_len; i++) pkt.payload.push_back(byte'(i + 'hA0)); döngüsüyle payload'ı üretir; byte'(...) casting ile değer 8-bit'e sığdırılır.
  • print_packet(...) void döndüren bir fonksiyondur; pkt.pkt_type.name() ile enum ismini ve %-4s gibi hizalı biçim belirteçleriyle tek satırlık özet basar.
  • initial bloğunda pkt_queue.push_back(create_packet(...)) ile 8 paket üretilir; bazıları (#5, #8) bilinçli olarak valid = 0 (geçersiz) işaretlenir.
  • Filtreleme adımları find with kullanır: item.pkt_type == PKT_DATA (yalnızca DATA), item.valid == 1 (geçerliler), item.length > 50 (büyük payload'lar) ve item.dst_addr == 16'h0002 (belirli hedef). Her biri sonucu filtered kuyruğuna yazar.
  • İstatistik bölümünde lengths adlı yardımcı kuyruğa tüm length değerleri toplanır; lengths.sum(), min(), max() ve sort() ile özet üretilir.
  • FIFO işleme bölümünde while (pkt_queue.size() > 0) döngüsü pkt_queue.pop_front() ile paketleri ekleniş sırasıyla tüketir; sonunda kuyruk boşalır.

Önemli Noktalar

  • Bir struct içinde dinamik diziler ve kuyruklar (byte payload [$]) barındırabilirsiniz; bu, değişken uzunluklu paketleri modellemenin doğal yoludur.
  • Paket üretimini bir fonksiyona (create_packet) ayırmak, kodu tekrar etmeden çok sayıda paket oluşturmayı sağlar; bu, doğrulamada yeniden kullanılabilirliğin temelidir.
  • find with (item.alan == deger) ifadesinde item her elemanı temsil eder ve struct alanlarına nokta ile erişilir; bu, koleksiyonları okunaklı biçimde filtrelemenin güçlü bir yoludur.
  • İstatistik almak için verileri ayrı bir kuyruğa toplayıp sum/min/max/sort uygulamak, struct kuyruğunun tamamını sıralamaktan daha pratiktir.
  • byte'(i + 'hA0) gibi açık casting, değerin hedef tipe (8-bit) güvenle sığmasını sağlar ve istenmeyen genişlik uyarılarını önler.
  • FIFO tüketiminde her zaman size() > 0 koşulunu kontrol edin; boş kuyrukta pop_front çağırmaktan kaçının.