Diziler (Arrays)
Gün 1: SystemVerilog'a Giriş ve Veri Tipleri | Sabit boyutlu, dinamik ve ilişkisel diziler
Bu derste SystemVerilog'un üç temel dizi türünü, hangi senaryoda hangisinin uygun olduğunu ve yerleşik dizi metodlarını (sum, min, max, sort, unique...) öğreneceğiz.
Aynı köşeli parantez, farklı kader.
Boyutu ne zaman bilirsin? Anahtarların ne kadar seyrek? Cevap hangi diziyi seçeceğini söyler.
fixed
int a [5]; Bellek baştan ayrılır, hepsi yan yana. Hızlı ama sabit.
dynamic
new[N] ile boyut belirlenir; new[M](eski) ile büyürken veriyi taşır.
associative
int a [string]; Sadece yazılan girdiler bellek harcar.
Belleği ve metodları canlı izle.
Bir sekme seç, altındaki düğmelerle sırayla komut çalıştır. Sol tarafta hücrelerin gerçekte ne yaptığını gör.
KAYNAK KODfixed_arr
DURUMcanlı
SİMÜLATÖR ÇIKTISI$display
Hangi diziyi seçmelisin?
Aklında kalsın.
new[N] ile ayır; büyütürken new[M](eski) yaz, yoksa veri sıfırlanır.sum, min, max, sort, rsort, shuffle, unique — hazır kullan.foreach her türü gezerÇok boyutlu dizide foreach (m[i, j]) ile tüm indeksler tek satırda.a[5] (5 elemanlı) yazmak hata/uyarı üretir; her zaman size()'a güven.Üç Dizi Türü
SystemVerilog, ihtiyaca göre seçilen üç ana dizi türü sunar:
- Sabit boyutlu (fixed-size) diziler: Boyut derleme zamanında bellidir (
int fixed_arr [5];). Çok boyutlu olabilirler (int matrix [3][4];). Bellek önceden ayrılır, erişim hızlıdır. - Dinamik (dynamic) diziler: Boyut çalışma zamanında
new[]ile belirlenir (int dyn_arr [];). Gerektiğinde yeniden boyutlandırılabilir vedelete()ile temizlenebilir. - İlişkisel (associative) diziler: Anahtar–değer eşlemesi yapar (
int assoc_arr [string];). Çok büyük ama seyrek (sparse) adres uzaylarını modellemek için idealdir; yalnızca yazılan girdiler için bellek harcar.
Dizi Metodları
SystemVerilog dizilerde doğrudan kullanılabilen güçlü metodlar sağlar:
- İndirgeme:
sum(),min(),max() - Sıralama/düzen:
sort(),rsort()(tersten),shuffle()(karıştır) - Filtreleme:
unique()ile tekrarsız elemanlar - Sorgu (associative):
num()eleman sayısı,exists()anahtar var mı
foreach döngüsü, indeksleri elle yönetmeden tüm dizi türlerini gezmenin en pratik yoludur; çok boyutlu dizilerde foreach (matrix[i, j]) gibi birden çok indeks kullanılabilir.
Kaynak Kod
// =============================================================================
// GUN 1 - Konu 5: Diziler (Arrays): Sabit, Dinamik, Iliskisel
// =============================================================================
module diziler;
// -------------------------------------------------------------------------
// SABIT BOYUTLU DIZILER (Fixed-Size Arrays)
// -------------------------------------------------------------------------
int fixed_arr [5]; // 5 elemanli unpacked dizi
logic [7:0] vec_arr [3]; // 3 elemanli unpacked dizi; her eleman 8-bit packed vektor
int matrix [3][4]; // 2 boyutlu dizi (3 satir, 4 sutun)
// -------------------------------------------------------------------------
// DINAMIK DIZILER (Dynamic Arrays)
// -------------------------------------------------------------------------
int dyn_arr []; // Boyut calisma zamaninda belirlenir
// -------------------------------------------------------------------------
// ILISKISEL DIZILER (Associative Arrays)
// -------------------------------------------------------------------------
int assoc_arr [string]; // String anahtarli
int sparse_mem [int]; // Int anahtarli
initial begin
$display("=== SystemVerilog Diziler ===\n");
// --- Sabit Boyutlu Dizi ---
$display("--- Sabit Boyutlu Diziler ---");
fixed_arr = '{10, 20, 30, 40, 50};
foreach (fixed_arr[i])
$display(" fixed_arr[%0d] = %0d", i, fixed_arr[i]);
// 2D dizi
$display("\n 2D Matris (3x4):");
foreach (matrix[i, j])
matrix[i][j] = (i * 4) + j;
foreach (matrix[i]) begin
$write(" Satir %0d: ", i);
foreach (matrix[i][j])
$write("%3d ", matrix[i][j]);
$display();
end
// Dizi metodlari
$display("\n Dizi Metodlari:");
$display(" sum = %0d", fixed_arr.sum());
$display(" min = %0d", fixed_arr.min());
$display(" max = %0d", fixed_arr.max());
$display(" unique = %p", fixed_arr.unique());
// Siralama
fixed_arr.rsort();
$display(" rsort = %p", fixed_arr);
fixed_arr.shuffle();
$display(" shuffle = %p", fixed_arr);
// --- Dinamik Dizi ---
$display("\n--- Dinamik Diziler ---");
dyn_arr = new[5];
foreach (dyn_arr[i]) dyn_arr[i] = (i + 1) * 100;
$display(" Baslangic boyut = %0d", dyn_arr.size());
foreach (dyn_arr[i]) $display(" dyn_arr[%0d] = %0d", i, dyn_arr[i]);
// Boyut degistirme (mevcut veriyi koruyarak)
dyn_arr = new[8](dyn_arr);
dyn_arr[5] = 600; dyn_arr[6] = 700; dyn_arr[7] = 800;
$display("\n Yeni boyut = %0d", dyn_arr.size());
foreach (dyn_arr[i]) $display(" dyn_arr[%0d] = %0d", i, dyn_arr[i]);
// Silme
dyn_arr.delete();
$display(" Silme sonrasi boyut = %0d", dyn_arr.size());
// --- Iliskisel Dizi ---
$display("\n--- Iliskisel Diziler ---");
// String anahtarli
assoc_arr["sifirlama"] = 0;
assoc_arr["baslat"] = 1;
assoc_arr["durdur"] = 2;
assoc_arr["hata"] = 99;
$display(" Eleman sayisi = %0d", assoc_arr.num());
if (assoc_arr.exists("hata"))
$display(" 'hata' anahtari mevcut, deger = %0d", assoc_arr["hata"]);
// foreach ile gezinme
foreach (assoc_arr[key])
$display(" assoc_arr[\"%s\"] = %0d", key, assoc_arr[key]);
// Seyrek bellek modeli
$display("\n Seyrek Bellek Modeli:");
sparse_mem[32'h0000] = 'hAA;
sparse_mem[32'h1000] = 'hBB;
sparse_mem[32'hFFFF] = 'hCC;
foreach (sparse_mem[addr])
$display(" MEM[0x%04h] = 0x%02h", addr, sparse_mem[addr]);
$display("\n=== Diziler Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
fixed_arr = '{10, 20, 30, 40, 50};ile sabit boyutlu dizi toplu atama (array literal) ile doldurulur veforeach (fixed_arr[i])ile yazdırılır.int matrix [3][4];iki boyutlu dizidir.foreach (matrix[i, j]) matrix[i][j] = (i * 4) + j;tek satırda her iki indeksi birden gezer; ardından satır satır basılır.- Dizi metodları
fixed_arrüzerinde gösterilir:sum()toplamı,min()/max()uç değerleri,unique()tekrarsız elemanları döndürür.rsort()diziyi büyükten küçüğe sıralar,shuffle()rastgele karıştırır (yerinde değiştirir). dyn_arr = new[5];dinamik diziyi 5 elemanlı oluşturur;foreachile(i + 1) * 100değerleri atanır.dyn_arr.size()anlık boyutu verir.dyn_arr = new[8](dyn_arr);diziyi 8 elemana büyütürken mevcut veriyi korur (parantez içindekidyn_arreski içeriği taşır); ardındandyn_arr[5],[6],[7]elle doldurulur.dyn_arr.delete();diziyi tamamen boşaltır, boyut0olur.- İlişkisel dizide
assoc_arr["hata"] = 99;gibi string anahtarlı girdiler eklenir;assoc_arr.num()eleman sayısını,assoc_arr.exists("hata")anahtarın varlığını sorgular.foreach (assoc_arr[key])ile anahtar üzerinden gezilir. sparse_mem[32'h0000],[32'h1000],[32'hFFFF]girdileri seyrek bellek modelini gösterir: 64K'lık bir adres uzayında yalnızca 3 girdi için bellek harcanır.
Önemli Noktalar
- Doğru türü seçin: Boyut sabitse fixed-size, çalışma zamanında değişiyorsa dynamic, anahtar–değer veya seyrek adresleme gerekiyorsa associative dizi kullanın.
- Dinamik diziyi büyütürken eski veriyi korumak için
new[N](eski_dizi)biçimini kullanın; aksi hâlde dizi yeni boyutta sıfırlanır. - İlişkisel diziler bellek açısından verimlidir ama erişim sırası tanımlı değildir; sırayı önemsiyorsanız anahtarları ayrıca sıralayın.
unique(),min(),max()gibi metodlar yeni bir kuyruk (queue) döndürür; orijinal diziyi değiştirmezler. Buna karşılıksort(),rsort(),shuffle()diziyi yerinde değiştirir.- Çok boyutlu dizilerde
foreach (matrix[i, j])sözdizimi, iç içe döngülere göre daha kısa ve okunaklıdır. - İlişkisel bir anahtara erişmeden önce
exists()ile kontrol etmek, tanımsız girdi okumaktan kaynaklı sürprizleri önler. Daha da önemlisi: var olmayan bir anahtarı okumak (x = assoc_arr["yok"]) çoğu simülatörde uyarı verip varsayılan değer döndürürken, ona yazmak o anahtarı sessizce oluşturur.if (sparse_mem[addr] == 0)gibi masum bir okuma bile bazı araçlarda girdi yaratabilir;exists()bu belirsizliği ortadan kaldırır. logic [7:0] vec_arr [3]bildiriminde köşeli parantezlerin yeri anlamı belirler: tip adının solundaki[7:0]packed boyuttur (bit vektörü), değişken adının sağındaki[3]unpacked boyuttur (eleman sayısı).vec_arr[1][3]ifadesi 1. elemanın 3. bitini verir.
Packed ve Unpacked Boyutlar
Packed (logic [7:0] x) |
Unpacked (logic x [8]) |
|
|---|---|---|
| Nerede yazılır? | Tip ile değişken adı arasında | Değişken adının sağında |
| Bellekte | Bitişik tek vektör | Ayrı elemanlar |
| Tek parça atama | x = 8'hFF; |
x = '{default: 1}; |
| Dilimleme | x[3:0] geçerli |
x[3:0] → 4 elemanlı alt dizi |
| Eleman tipi | Yalnızca bit türleri | Her tip (int, string, struct, class...) |
| Tipik kullanım | Sinyaller, bus veri yolu | Bellek modelleri, transaction listeleri |
Hangi Dizi Türü, Hangi Senaryo?
| Senaryo | Tür | Gerekçe |
|---|---|---|
| 256 girdili register dosyası modeli | Sabit boyutlu logic [31:0] rf [256] |
Boyut bellidir, erişim en hızlı |
| Payload uzunluğu transaction'a göre değişen paket | Dinamik byte payload [] |
Boyut new[n] ile çalışma zamanında |
| 4 GB adres uzayında yalnızca birkaç KB yazılan bellek | İlişkisel logic [7:0] mem [logic [31:0]] |
Yalnızca kullanılan adresler için bellek |
| İsimle eşleşen konfigürasyon değerleri | İlişkisel int cfg [string] |
Anahtar metin olabilir |
| Scoreboard'da beklenen değer listesi (ekle/çıkar) | Kuyruk (sonraki ders) | İki uçtan verimli ekleme/çıkarma |
Sık Yapılan Hatalar
new[N]ile veriyi kaybetmek:dyn_arr = new[8];eski içeriği siler. Korumak içinnew[8](dyn_arr)yazın.- İlişkisel dizide sıra beklemek:
foreachilişkisel diziyi anahtar sırasına göre gezer (sayısal anahtarlarda artan, string'lerde sözlük sırası); ekleme sırası korunmaz. Ekleme sırası önemliyse kuyruk kullanın. sum()'ın genişliğini unutmak:bit [7:0] arr [4]içinarr.sum()8-bit'te toplanır ve taşabilir.arr.sum() with (int'(item))ile genişletin (bu konu Gün 3'teki kısıtlamalarda tekrar karşımıza çıkacak).unique()sonucunu diziye atamak:unique(),find()gibi metodlar kuyruk döndürür; sonucuint q[$]tipinde bir değişkene alın.
Kendinizi Deneyin
matrixdizisiniforeach (matrix[i, j])ile gezerken yalnızca köşegen elemanları (i == j) 99 yapın ve yazdırın.dyn_arr'ınew[3](dyn_arr)ile küçültün. Hangi elemanlar kaldı? Bu davranışı açıklayın.sparse_mem'eforeachile girmeden öncesparse_mem.first(addr)/sparse_mem.next(addr)metodlarını araştırın ve aynı çıktıyıdo...whiledöngüsüyle üretin.fixed_arr.find with (item > 25)ifadesini kullanıp sonucu bir kuyruğa alın;%pile yazdırın.
Hızlı Kontrol: int a [int]; ile int a []; arasındaki fark nedir?
int a [int] ilişkisel dizidir: anahtar tipi int, yalnızca yazılan anahtarlar için yer ayrılır, new[] gerekmez. int a [] ise dinamik dizidir: indeksler 0'dan size()-1'e kadar bitişiktir ve kullanmadan önce a = new[N] ile boyutlandırılmalıdır.