Fonksiyonel Kapsam
Gün 5: Arayüzler, Assertion ve Coverage | covergroup, coverpoint, bins, cross coverage
Bu derste fonksiyonel kapsam (functional coverage) ile testlerimizin tasarımın ne kadarını gerçekten denediğini nasıl ölçeceğimizi öğreneceğiz. covergroup, coverpoint, bins ve cross yapılarını bir ALU örneği üzerinden inceleyeceğiz.
Fonksiyonel Kapsam Neden Önemli?
Rastgele test (constrained random) ile binlerce işlem üretebilirsiniz, ama "her senaryoyu denedim mi?" sorusunun cevabı belirsiz kalır. Fonksiyonel kapsam, doğrulama planındaki senaryoların gerçekten gerçekleşip gerçekleşmediğini sayısal olarak ölçer:
- Doğrulamanın bittiğine karar verdirir: Kapsam %100'e ulaşmadan doğrulama tamamlanmış sayılmaz.
- Test boşluklarını gösterir: Hangi
bin'in hiç dolmadığını görüp eksik senaryoları belirlersiniz. - Kod kapsamından farklıdır: Kod kapsamı "kod satırı çalıştı mı?" sorusunu, fonksiyonel kapsam ise "anlamlı senaryo test edildi mi?" sorusunu yanıtlar.
Temel Kavramlar
covergroup: Birbiriyle ilişkili kapsam noktalarını gruplayan yapıdır.with function sample(...)ile dışarıdan veri alarak örnekleme yapabilir.coverpoint: İzlenecek bir değişkeni/ifadeyi temsil eder.bins: Bir coverpoint'in değer aralıklarını kovalara böler. Her kovanın en az bir kez dolması beklenir.illegal_bins: Asla oluşmaması gereken değerleri işaretler; oluşursa hata verir.cross: İki coverpoint'in kombinasyonlarını ölçer (örn. her işlem × her operand aralığı). Köşe durumlarını yakalamada güçlüdür.
Kaynak Kod
// =============================================================================
// GUN 5 - Konu 5: Fonksiyonel Kapsam (Functional Coverage)
// =============================================================================
class ALU_Transaction;
typedef enum logic [2:0] {ADD, SUB, AND, OR, XOR, SHL, SHR} op_e;
rand op_e operation;
rand logic [7:0] operand_a;
rand logic [7:0] operand_b;
logic [15:0] result;
constraint c_operands {
operand_a inside {[0:255]};
operand_b inside {[0:255]};
}
function void compute();
case (operation)
ADD: result = operand_a + operand_b;
SUB: result = operand_a - operand_b;
AND: result = operand_a & operand_b;
OR: result = operand_a | operand_b;
XOR: result = operand_a ^ operand_b;
SHL: result = operand_a << operand_b[2:0];
SHR: result = operand_a >> operand_b[2:0];
endcase
endfunction
endclass
module functional_coverage;
ALU_Transaction txn;
// =========================================================================
// COVERGROUP: Kapsam grubu tanimi
// =========================================================================
covergroup alu_cg with function sample(
ALU_Transaction::op_e op,
logic [7:0] a, logic [7:0] b, logic [15:0] res
);
// --- COVERPOINT: Islem kapsanmasi ---
cp_operation: coverpoint op {
bins add_bin = {ALU_Transaction::ADD};
bins sub_bin = {ALU_Transaction::SUB};
bins and_bin = {ALU_Transaction::AND};
bins or_bin = {ALU_Transaction::OR};
bins xor_bin = {ALU_Transaction::XOR};
bins shl_bin = {ALU_Transaction::SHL};
bins shr_bin = {ALU_Transaction::SHR};
}
// --- COVERPOINT: Operand A araliklari ---
cp_op_a: coverpoint a {
bins zero = {0};
bins low = {[1:63]};
bins mid = {[64:191]};
bins high = {[192:254]};
bins max_val = {255};
}
// --- COVERPOINT: Operand B araliklari ---
cp_op_b: coverpoint b {
bins zero = {0};
bins low = {[1:63]};
bins mid = {[64:191]};
bins high = {[192:254]};
bins max_val = {255};
}
// --- COVERPOINT: Sonuc araliklari ---
cp_result: coverpoint res {
bins zero = {0};
bins small = {[1:255]};
bins medium = {[256:65534]};
bins overflow = {65535};
}
// --- COVERPOINT: Kose durumlari ---
cp_corner: coverpoint a {
bins boundaries[] = {0, 1, 127, 128, 254, 255};
illegal_bins never = default;
}
// --- CROSS: Islem x Operand A araligi ---
cx_op_a: cross cp_operation, cp_op_a;
// --- CROSS: Islem x Operand B araligi ---
cx_op_b: cross cp_operation, cp_op_b;
endgroup
// =========================================================================
alu_cg cg;
initial begin
$display("=== Fonksiyonel Kapsam (Functional Coverage) ===\n");
txn = new();
cg = new();
// Rastgele test dongusu
$display("--- 200 Rastgele Islem ---");
repeat (200) begin
assert(txn.randomize()) else $fatal(1, "Randomize hata!");
txn.compute();
cg.sample(txn.operation, txn.operand_a, txn.operand_b, txn.result);
end
// Yonlendirilmis testler (kose durumlari)
$display("--- Yonlendirilmis Kose Testleri ---");
begin
logic [7:0] corners [] = '{0, 1, 127, 128, 254, 255};
foreach (corners[i]) begin
foreach (corners[j]) begin
assert(txn.randomize() with {
operand_a == corners[i];
operand_b == corners[j];
}) else continue;
txn.compute();
cg.sample(txn.operation, txn.operand_a, txn.operand_b, txn.result);
end
end
end
// Kapsam raporu
$display("\n--- Kapsam Raporu ---");
$display(" Toplam Kapsam : %.1f%%", cg.get_coverage());
$display(" cp_operation : %.1f%%", cg.cp_operation.get_coverage());
$display(" cp_op_a : %.1f%%", cg.cp_op_a.get_coverage());
$display(" cp_op_b : %.1f%%", cg.cp_op_b.get_coverage());
$display(" cp_result : %.1f%%", cg.cp_result.get_coverage());
$display("\n=== Fonksiyonel Kapsam Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
ALU_Transactionsınıfı:op_eenum'u (ADD,SUB,AND,OR,XOR,SHL,SHR) ile işlem türünü tanımlar.operation,operand_a,operand_brastgele üretilir;c_operandskısıtı operandları 0-255 aralığına çeker.computefonksiyonu seçilen işleme göreresult'u hesaplar (kaydırmalardaoperand_b[2:0]kullanılır).covergroup alu_cg:with function sample(...)ile işlem, iki operand ve sonucu dışarıdan alır.cp_operation: Yedi ALU işleminin her birini ayrı birbinile izler.cp_op_a/cp_op_b: Operandları anlamlı aralıklara böler:zero,low[1:63],mid[64:191],high[192:254],max_val255.cp_result: Sonucuzero,small,medium,overflowaralıklarına ayırır.cp_corner:bins boundaries[] = {0, 1, 127, 128, 254, 255}ile köşe değerleri tek tek izler;illegal_bins never = defaultbu altı değer dışındaki her durumu yasadışı sayar.cx_op_a/cx_op_b: İşlem ile operand aralıklarının çapraz kombinasyonlarını (cross) ölçer.
functional_coverage(top):txnvecgnesneleri oluşturulur. Öncerepeat(200)döngüsünde rastgele işlemler üretilipcomputeedilir vecg.sample(...)ile örneklenir. Ardındancornersdizisi üzerinde iç içeforeachile yönlendirilmiş köşe testleri çalıştırılır (randomize() with {...}ile operandlar sabitlenir). Son olarakget_coverage()çağrılarıyla toplam ve coverpoint bazlı kapsam raporlanır.
Önemli Noktalar
illegal_binsile geçersiz değerleri yakalayın:cp_corneriçindekiillegal_bins never = default, beklenmedik bir değer örneklenirse simülasyonda hata üretir; bu, sessiz kapsam boşluklarını engeller.defaultbin tuzağı:defaultbin, kalan tüm değerleri toplar ama genellikle kapsam yüzdesine sayılmaz. Anlamlı senaryoları açıkça adlandırılmışbins'lerle ifade edin.crossile köşe kombinasyonları: Tek tek coverpoint'ler %100 olsa bile,cx_op_a/cx_op_bçaprazları "her işlemi her aralıkla denedim mi?" sorusunu yanıtlar; gerçek boşluklar çoğunlukla burada görünür.- Rastgele + yönlendirilmiş birlikte: Rastgele test geniş alanı tarar, ama
255veya0gibi köşe değerlerine nadiren isabet eder. Kod, bunlarırandomize() withile bilinçli olarak zorlar. sample()'ı doğru anda çağırın: Kapsam ancaksampleçağrıldığında güncellenir; veri kararlıyken (buradacomputesonrası) örneklemek doğru sonuç verir.- Anlamlı
binsaralıkları seçin: Kovaları rastgele değil, tasarımın davranışının değiştiği sınırlara göre bölmek (örn. taşma içinoverflow = {65535}) kapsamı anlamlı kılar.