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 EDA Playground'da kendinizi deneyin. Sonrasında buradakiyle karşılaştırabilirsiniz. Başarılar!
Adım Adım Görev Listesi
Çözüme bakmadan önce aşağıdaki adımları kendiniz tamamlamayı deneyin. Her adım bir öncekinin üzerine kurulur:
- Veri modeli:
PKT_DATA,PKT_ACK,PKT_NACK,PKT_CTRLdeğerlerini taşıyan 2-bitlik birenumveid,pkt_type,src_addr,dst_addr,payload[$],length,validalanlarını içeren birstructtanımlayın. - Üretici fonksiyon: Parametrelerden bir paket üretip döndüren
create_packet(...)fonksiyonu yazın. Payload'upayload_lenkadarpush_backile doldurun. - Yazdırıcı fonksiyon: Tek satırda özet basan
voidbirprint_packet(...)yazın; enum ismi için.name()kullanın. - Kuyruğu doldurun: En az 8 paket üretin; birkaçını bilinçli olarak
valid = 0yapın. - Filtreleyin:
find withkullanarak (a) yalnızca DATA paketleri, (b) geçerli paketler, (c) payload'u 50 bayttan büyük paketler, (d) hedef adresi0x0002olan paketleri ayrı ayrı bulun. - İstatistik: Payload uzunluklarını ayrı bir kuyruğa toplayıp
sum,min,maxvesortuygulayın. - Tüketin: Kuyruğu
while (size() > 0)+pop_front()ile boşaltın.
İpucu: Takıldığınız adımda yalnızca o adımın çözümüne bakın; tüm kodu bir anda kopyalamak öğrenmeyi kısa devre yapar.
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. create_packetbir struct döndürür ve struct'lar değer tipidir:pkt_queue.push_back(create_packet(...))çağrısında paketin tüm alanları (payload kuyruğu dahil) kuyruğa kopyalanır. Gün 2'de sınıflara geçince aynı satır bir handle kopyalayacak; bu fark derin/sığ kopya dersinde kritik olacak.- Lab'daki
filtered = pkt_queue.find with (...)satırı her çağrıdafiltered'ın eski içeriğini tamamen değiştirir. Sonuçları biriktirmek istersenizfiltered = {filtered, pkt_queue.find with (...)}biçiminde birleştirmeniz gerekir.
Çıktıyı Okuma Rehberi
Çalıştırdığınızda şu kontrolleri yapın:
| Bölüm | Beklenen sonuç | Neden |
|---|---|---|
| 2. Filtre (DATA) | 5 paket (#1, #3, #5, #7, #8) | 8 paketin 5'i PKT_DATA |
| 3. Filtre (Geçerli) | 6 paket | #5 ve #8 valid = 0 |
| 4. Filtre (Len > 50) | 3 paket (#1, #3, #7) | 64, 128, 256 > 50 |
| 5. Filtre (Dst = 0x0002) | 3 paket (#1, #3, #7) | Hedef alanı 16'h0002 olanlar |
| 6. İstatistik | Toplam 504, min 0, max 256 | 64+0+128+0+32+8+256+16 |
Sayılarınız tabloyla uyuşmuyorsa önce create_packet çağrılarındaki argüman sırasını kontrol edin; en sık hata src/dst adreslerinin yer değiştirmesidir.
Ek Görevler (Zorluk Artan)
- Kolay: Paketleri
lengthdeğerine göre azalan sırada listeleyin (rsort with (item.length)ya da ayrı kuyruk). - Orta: Her
pkt_typeiçin kaç paket olduğunuint count [pkt_type_e]ilişkisel dizisiyle sayın ve.name()ile yazdırın. - Orta: Payload'un basit bir sağlama toplamını (
checksum) hesaplayanfunction byte calc_checksum(network_packet_t p)yazın (tüm baytların XOR'u) ve struct'achecksumalanı ekleyin. - Zor:
src_addr == dst_addrolan paketleri geçersiz işaretleyen birvalidate_packets(ref network_packet_t q[$])fonksiyonu yazın.refargümanın neden gerektiğini açıklayın (Gün 2'deref'i ayrıntılı göreceksiniz).
Hızlı Kontrol: find with (item.valid == 1) ifadesindeki item nereden geliyor?
item, with yan tümcesinde SystemVerilog'un örtük olarak tanımladığı yineleme değişkenidir; kuyruğun o anki elemanını temsil eder. İsterseniz find(p) with (p.valid == 1) yazarak kendi adınızı da verebilirsiniz.