randomize() Metodu
Gün 3: Rastgele Üretim ve Kısıtlamalar | Rastgele üretim, inline constraint, hata kontrolü
Bu derste her rastgele sınıfın kalbi olan randomize() metodunu derinlemesine inceleyeceğiz: temel kullanımını, satır içi (inline) kısıtlama ekleyen with sözdizimini, yalnızca seçili değişkenleri rastgeleleştirmeyi ve dönüş değeri ile hata kontrolünü öğreneceğiz.
randomize() Metodu
randomize(), rastgele üyeleri olan her sınıfın otomatik olarak sahip olduğu, yerleşik (built-in) bir sınıf metodudur. Çağrıldığında sınıftaki tüm rand/randc değişkenlerine, tanımlı constraint blokları ve verilen kısıtlamaları sağlayacak şekilde rastgele değerler atar.
Metot bir bit döndürür:
1→ çözüm bulundu, değişkenler güncellendi.0→ kısıtlamalar çakıştı (çözüm yok), değişkenler değişmeden kalır.
Bu yüzden dönüş değeri asla göz ardı edilmemelidir.
Satır İçi Kısıtlama: with { ... }
randomize() çağrısına with { ... } ekleyerek, sınıfta tanımlı kalıcı kısıtlamalara ek olarak yalnızca o çağrıya özel geçici kısıtlamalar verebilirsiniz. Bu kısıtlamalar sınıf içindeki blocklarla AND ilişkisiyle birleşir.
Seçici Randomize
randomize() metoduna argüman olarak değişken adları verilirse (randomize(data, size) gibi), yalnızca o değişkenler rastgeleleştirilir; geri kalanı o anki değerlerinde sabit tutulur. Bu, belirli bir alanı sabit tutup diğerlerini değiştirmek istediğinizde çok kullanışlıdır.
Hata Kontrolü ve assert
Endüstride yaygın kalıp, randomize çağrısını bir assert(...) else $fatal(...) içine almaktır. Böylece çözülemeyen bir kısıtlama anında ve net bir mesajla yakalanır.
Kaynak Kod
// =============================================================================
// GUN 3 - Konu 2: randomize() Metodu ve Hata Kontrolu
// =============================================================================
class Transaction;
rand logic [15:0] address;
rand logic [31:0] data;
rand bit [2:0] size;
rand bit read_write; // 0=read, 1=write
constraint addr_range {
address inside {[16'h0000 : 16'h0FFF]};
}
function void display(string prefix = "");
$display(" %sAddr=0x%04h, Data=0x%08h, Size=%0d, R/W=%s",
prefix, address, data, size,
read_write ? "WRITE" : "READ");
endfunction
endclass
module randomize_metodu;
initial begin
Transaction txn;
int success;
$display("=== randomize() Metodu ===\n");
txn = new();
// --- Temel randomize ---
$display("--- Temel randomize() ---");
repeat (5) begin
success = txn.randomize();
if (success)
txn.display();
else
$display(" HATA: Randomize basarisiz!");
end
// --- randomize() with (inline constraint) ---
$display("\n--- randomize() with (Satir ici kisitlama) ---");
repeat (5) begin
success = txn.randomize() with {
address >= 16'h0100 && address <= 16'h01FF;
data[31:16] == 16'h0000;
read_write == 1;
};
if (success)
txn.display("inline: ");
else
$display(" HATA: Inline randomize basarisiz!");
end
// --- Belirli degiskenleri sabit tutma ---
$display("\n--- Secici Randomize ---");
txn.address = 16'h0ABC;
repeat (3) begin
// address sabit, sadece digerleri rastgele
success = txn.randomize(data, size, read_write);
txn.display("addr sabit: ");
end
// --- randomize() donus degeri kontrolu ---
$display("\n--- Hata Kontrolu ---");
success = txn.randomize() with { address == 16'hFFFF; }; // Constraint ile cakisabilir
if (!success)
$display(" Constraint cakismasi: 0xFFFF aralik disi (0x0000-0x0FFF)");
// Dogru kullanim: assert ile
$display("\n--- assert ile Kontrol ---");
// assert(txn.randomize()) else $fatal(1, "Randomize HATA!");
if (txn.randomize())
txn.display("assert OK: ");
else
$fatal(1, "Randomize basarisiz!");
$display("\n=== randomize() Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
Transactionsınıfındaaddress,data,sizeveread_writerastgele üyeleri tanımlanır.addr_rangeadlı constraint,addressdeğeriniinside {[16'h0000 : 16'h0FFF]}aralığına sınırlar — yani adres her zaman 0x0000–0x0FFF arasında kalır.- Temel randomize bölümünde
success = txn.randomize()çağrısının dönüş değeri bir değişkene atanır veif (success)ile kontrol edilir; başarısızsa hata basılır. - Satır içi kısıtlama bölümünde
randomize() with { ... }kullanılarakaddress0x0100–0x01FF aralığına,data[31:16]sıfıra veread_write1'e (WRITE) sabitlenir. Bu kısıtlamalaraddr_rangeile çakışmaz çünkü 0x0100–0x01FF, izin verilen 0x0000–0x0FFF aralığının içindedir. - Seçici randomize bölümünde önce
txn.address = 16'h0ABCile adres elle ayarlanır, ardındantxn.randomize(data, size, read_write)çağrılır. Argüman listesindeaddressolmadığı için adres0x0ABColarak sabit kalır, yalnızca diğer üç alan değişir. - Hata kontrolü bölümünde bilinçli olarak çakışan bir kısıtlama (
address == 16'hFFFF) verilir. 0xFFFF,addr_range'in izin verdiği aralığın dışında olduğundanrandomize()başarısız olur (0döner) ve değişkenler değişmez. - Son bölümde doğru kalıp gösterilir:
if (txn.randomize())...else $fatal(...). Yorum satırındakiassert(txn.randomize()) else $fatal(...)ise endüstride en yaygın yazım biçimidir.
Önemli Noktalar
- Çakışan kısıtlamalarda eski değerler kalır.
randomize()0döndüğünde değişkenler güncellenmez; bu yüzden başarısız bir çağrının ardından "eski" değerlerle çalışma riski vardır. - Satır içi kısıtlamalar sınıf kısıtlamalarını ezmez, onlarla birleşir.
withiçindeki ifadeler mevcut constraint blocklarıyla AND'lenir; bu nedenle sınıf kısıtlamasıyla çelişen bir inline kısıtlama çözümsüzlüğe yol açar. - Seçici randomize ile sabit tutulan alanların değerini önceden ayarlayın.
randomize(...)argüman listesi dışında kalan rastgele alanlar, mevcut değerlerinde dondurulur. - Üretimde
assert(...) else $fatal(...)kalıbını tercih edin. Bu, çözülemeyen kısıtlamaları sessizce geçiştirmek yerine hemen, açık bir mesajla raporlar. - Hangi değerlerin köşe durum oluşturduğunu test ederken (örneğin aralık sınırları) kasıtlı çakışmalarla constraint mantığınızı doğrulamak iyi bir pratiktir.