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) kuyrukint bounded_q [$:9];→ en fazla 10 elemanlı sınırlı (bounded) kuyruk- Kuyruk elemanları
structgibi 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ışıkq_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 yerelvaldeğişkenine alınır.q_int.insert(2, 25);indeks 2'ye25ekler;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 hepsifoundadlı 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_pktbir struct kuyruğudur.q_pkt.push_back('{id: 1, name: "READ", data: 'hAA});gibi struct literal'lar eklenir veforeachile alanları (id,name,data) yazdırılır.q_pkt_cksum.push_back('{id:1, default: 0});satırı struct literal'dadefaultanahtarını gösterir: açıkça verilmeyen tüm alanlar (data,cksum)0ile doldurulur. İkinci örnekte yalnızcadata: 123verilir, kalanlar yinedefault: 0olur.- Sonda FIFO kullanımı:
while (q_pkt.size() > 0)döngüsündeq_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çinpush_back+pop_backkullanın. find,find_index,min,max,uniquegibi metodlar yeni bir kuyruk döndürür; bu yüzden sonucu daima bir kuyruğa atayın (örnektekifoundgibi).withyan tümcesindekiitemörtük değişkendir; karmaşık elemanlardaitem.alan_adi(örneğinitem.pkt_type) şeklinde alanlara erişebilirsiniz.- Boş bir kuyrukta
pop_front/pop_backçağırmak tanımsız davranışa yol açar; çıkarmadan öncesize() > 0kontrolü yapın. structliteral'larındadefaultanahtarı, 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.