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) vestruct(network_packet_t) ile modelleyeceğiz. - Paketleri yeniden kullanılabilir bir fonksiyon (
create_packet) ile üretip bir kuyruğa ekleyeceğiz. find withfiltreleriyle 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_tiçindekibyte payload [$]alanı, struct'ın içinde dinamik bir veri tutar. - Fonksiyonlar:
create_packetbirstructdöndürürken,print_packetvoiddöndürerek yalnızca çıktı üretir. find withveitem: Karmaşık elemanlardaitem.pkt_type,item.valid,item.length,item.dst_addrgibi 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_eenum'u dört paket tipini (PKT_DATA,PKT_ACK,PKT_NACK,PKT_CTRL)logic [1:0]tabanında tanımlar.network_packet_tstruct'ı bir paketin tüm alanlarını taşır:id,pkt_type,src_addr,dst_addr, dinamikbyte payload [$],lengthvevalid. Burada bir struct'ın içinde kuyruk barındırabildiğini görüyoruz.pkt_queuevefiltered,network_packet_ttipinde iki struct kuyruğudur.create_packet(...)fonksiyonu birnetwork_packet_tdöndürür. Alanları parametrelerden doldurur vefor (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(...)voiddöndüren bir fonksiyondur;pkt.pkt_type.name()ile enum ismini ve%-4sgibi hizalı biçim belirteçleriyle tek satırlık özet basar.initialbloğundapkt_queue.push_back(create_packet(...))ile 8 paket üretilir; bazıları (#5,#8) bilinçli olarakvalid = 0(geçersiz) işaretlenir.- Filtreleme adımları
find withkullanır:item.pkt_type == PKT_DATA(yalnızca DATA),item.valid == 1(geçerliler),item.length > 50(büyük payload'lar) veitem.dst_addr == 16'h0002(belirli hedef). Her biri sonucufilteredkuyruğuna yazar. - İstatistik bölümünde
lengthsadlı yardımcı kuyruğa tümlengthdeğerleri toplanır;lengths.sum(),min(),max()vesort()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
structiç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)ifadesindeitemher 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/sortuygulamak, 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() > 0koşulunu kontrol edin; boş kuyruktapop_frontçağırmaktan kaçının.