Constraint Blokları
Gün 3: Rastgele Üretim ve Kısıtlamalar | inside, dist, if-else, implication (->) kısıtlamaları
Bu derste constraint bloklarının en sık kullanılan yapı taşlarını öğreneceğiz: değer kümesi sınırlayan inside, olasılık dağılımı belirleyen dist, koşullu kısıtlama kuran if-else ve bir koşuldan sonuç türeten implication (->) operatörü.
Constraint Bloğu Nedir?
Bir constraint bloğu, bir sınıfın rastgele değişkenlerinin hangi değerleri alabileceğini tanımlayan kurallar kümesidir. randomize() çağrıldığında çözücü (solver), tüm aktif constraint bloklarını aynı anda sağlayan bir değer kombinasyonu bulmaya çalışır. Kısıtlamalar bildirimseldir (declarative): "ne olması gerektiğini" söylersiniz, "nasıl çözüleceğini" değil.
inside
inside operatörü bir değişkeni belirli bir değer kümesi veya aralık(lar)ı ile sınırlar. Birden fazla aralık verilebilir ve ! ile olumsuzlanarak (!(x inside {...})) bir kümenin dışında kalması da istenebilir.
dist — Olasılık Dağılımı
dist, değerlerin hangi olasılıkla seçileceğini belirler. İki ağırlık operatörü vardır:
:=→ ağırlık her bir değere ayrı ayrı uygulanır.:/→ ağırlık, belirtilen aralıktaki tüm değerlere eşit olarak bölüştürülür.
if-else ve implication (->)
if-elsekısıtlamaları, bir alanın değerine göre başka alanlara koşullu kurallar uygulamayı sağlar.- Implication (
->) ise "A ise B de olmalı" mantığını ifade eder.(koşul) -> (sonuç)biçiminde yazılır; koşul doğruysa sonuç da zorlanır, koşul yanlışsa sonuç üzerinde herhangi bir kısıtlama olmaz.
Kaynak Kod
// =============================================================================
// GUN 3 - Konu 3: Kisitlama Bloklari: inside, dist, if-else, implication
// =============================================================================
class ConfigPacket;
typedef enum logic [1:0] {IDLE, READ, WRITE, BURST} cmd_e;
rand cmd_e command;
rand logic [15:0] address;
rand logic [31:0] data;
rand int unsigned length;
rand bit [7:0] prio;
rand bit valid;
// --- inside: Deger kumesi kisitlamasi ---
constraint c_addr_inside {
address inside {[16'h0000:16'h0FFF], // Bolge 1
[16'h2000:16'h2FFF], // Bolge 2
[16'hF000:16'hFFFF]}; // Bolge 3
}
// --- dist: Olasilik dagilimi ---
constraint c_cmd_dist {
command dist {
READ := 40, // %40 okuma
WRITE := 40, // %40 yazma
BURST := 15, // %15 burst
IDLE := 5 // %5 bosta
};
}
constraint c_priority_dist {
prio dist {
[0:3] :/ 60, // Dusuk oncelik - %60 (/= esit dagilir: her biri %15)
[4:6] :/ 30, // Orta oncelik - %30
7 := 10 // Yuksek oncelik - %10
};
}
// --- if-else: Kosullu kisitlama ---
constraint c_data_ifelse {
if (command == READ) {
data == 32'h0; // Okumada veri sifir
length inside {[1:4]};
} else if (command == WRITE) {
data != 32'h0; // Yazmada veri sifir olamaz
length inside {[1:8]};
} else if (command == BURST) {
length inside {[4:16]}; // Burst uzun
} else {
length == 0; // IDLE
data == 0;
}
}
// --- implication (->): Sonuc kisitlamasi ---
constraint c_valid_impl {
(command != IDLE) -> (valid == 1); // IDLE degilse gecerli olmali
(command == IDLE) -> (valid == 0);
}
constraint c_burst_addr {
(command == BURST) -> (address[3:0] == 4'h0); // Burst hizali adres
}
// --- Sabit deger dislama ---
constraint c_no_zero_addr {
address != 16'h0000;
}
function void display();
$display(" CMD=%-5s | Addr=0x%04h | Data=0x%08h | Len=%2d | Pri=%0d | V=%0b",
command.name(), address, data, length, prio, valid);
endfunction
endclass
module constraint_bloklari;
initial begin
ConfigPacket pkt;
int cmd_counts [string];
$display("=== Constraint Bloklari ===\n");
pkt = new();
// --- Kisitlamali rastgele uretim ---
$display("--- 20 Rastgele Paket ---");
cmd_counts["IDLE"] = 0;
cmd_counts["READ"] = 0;
cmd_counts["WRITE"] = 0;
cmd_counts["BURST"] = 0;
repeat (20) begin
assert(pkt.randomize()) else $fatal(1, "Randomize hata!");
pkt.display();
cmd_counts[pkt.command.name()]++;
end
// --- Dagilim istatistikleri ---
$display("\n--- Komut Dagilimi (20 deneme) ---");
foreach (cmd_counts[key])
$display(" %s: %0d kez (%%%0d)", key, cmd_counts[key], cmd_counts[key]*5);
// --- inside dislama (~inside) ---
$display("\n--- Adres Dislama (~inside) ---");
repeat (5) begin
assert(pkt.randomize() with {
!(address inside {[16'h0000:16'h00FF]});
});
$display(" Addr = 0x%04h (0x0000-0x00FF disinda)", pkt.address);
end
$display("\n=== Constraint Bloklari Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
ConfigPacketsınıfı,cmd_eadında bir enum (IDLE,READ,WRITE,BURST) vecommand,address,data,length,prio,validrastgele üyelerini içerir.c_addr_insideconstraint'iaddress'i üç ayrı bölgeyle sınırlar: 0x0000–0x0FFF, 0x2000–0x2FFF ve 0xF000–0xFFFF. Bu, çoklu aralıklıinsidekullanımının tipik örneğidir.c_cmd_dist,commandenum'una bir dağılım atar:READveWRITE%40'ar,BURST%15,IDLE%5. Burada:=operatörü kullanıldığı için her ağırlık o tek değere uygulanır.c_priority_dist,:/operatörünü gösterir:[0:3] :/ 60ifadesinde %60'lık ağırlık dört değere eşit bölünür (her biri ~%15).7 := 10ise tek değere %10 verir.c_data_ifelse,commanddeğerine göre koşullu kurallar uygular. ÖrneğinREADdurumundadata == 0velength inside {[1:4]};WRITEdurumundadata != 0velength inside {[1:8]}olur.c_valid_implimplication kullanır:(command != IDLE) -> (valid == 1)ve(command == IDLE) -> (valid == 0). Böylece IDLE dışındaki komutlardavalidher zaman 1, IDLE'da 0 olur.c_burst_addr, BURST komutundaaddress[3:0] == 4'h0zorlayarak hizalı (aligned) adres garantisi verir.c_no_zero_addr,address != 16'h0000ile sıfır adresi tamamen dışlar.moduleiçinde 20 paket üretilir vecmd_countsadlı string-indeksli ilişkisel dizide her komutun kaç kez çıktığı sayılır; ardından dağılım yüzdeleri (cmd_counts[key]*5) yazdırılır.- Son bölümde
randomize() with { !(address inside {[16'h0000:16'h00FF]}); }ile satır içi olarak belirli bir adres aralığı dışlanır.
Önemli Noktalar
:=ile:/farkını karıştırmayın.:=ağırlığı her değere ayrı uygularken,:/ağırlığı aralıktaki değerlere eşit böler. Yanlış operatör beklenmedik dağılımlara yol açar.- Implication (
->) tek yönlüdür.(A) -> (B), yalnızca A doğruyken B'yi zorlar; A yanlışsa B serbesttir. Çift yönlü ilişki için her iki yönü de yazmak gerekir (kodda IDLE için yapıldığı gibi). - Tüm aktif constraint blocları aynı anda sağlanır. Çözücü, bloklar arasında çelişki varsa randomize'ı başarısız kılar; bu yüzden
if-else,insideve implication kurallarının birbiriyle tutarlı olduğundan emin olun. - Dağılım istatistiklerini doğrulamak için yeterli örnek üretin. 20 deneme dağılımın genel eğilimini gösterir, ancak küçük örneklemde gerçek yüzdelerden sapma normaldir.
insidearalıklarının kümülatif olarak en az bir geçerli değer içermesine dikkat edin; aksi halde diğer kısıtlamalarla birleştiğinde çözümsüzlük oluşabilir.