Coverage Tanımları
Gün 7: Bitirme Projesi - Bölüm 2 | ALU projesi için covergroup ve cross coverage
Coverage (kapsam), "DUT'u yeterince test ettik mi?" sorusunu ölçen bileşendir. ALU mimarimizde fonksiyonel kapsamı toplar: hangi işlemlerin, hangi operand değerlerinin ve hangi bayrak kombinasyonlarının gerçekten denendiğini sayısal olarak raporlar.
Coverage ve Mimarideki Yeri
Testlerin geçmesi tek başına yeterli değildir; önemli senaryoların uyarılmış olduğundan da emin olmak gerekir. İşte bunu functional coverage ölçer. Bu sınıf, scoreboard tarafından beslenir:
- Scoreboard her gözlenen transaction için
cov.sample(actual)çağırır. sample, ilgili alanlarıalu_cgcovergroup'una iletir ve kapsam noktaları güncellenir.
Sonuçta kapsam yüzdeleri, test setinin ne kadar kapsamlı olduğunu gösterir ve eksik kalan senaryoları ortaya çıkarır.
Coverpoint ve Cross Coverage
alu_cg covergroup'u şu kapsam noktalarını izler:
cp_opcode: Sekiz işlem kodunun her birinin denenip denenmediği.cp_op_a/cp_op_b: Operandların köşe değerleri ve aralıkları (sıfır, bir, orta, maksimum vb.).cp_flags: Üretilen bayrak kombinasyonları.cp_result: Sonuç büyüklüğü aralıkları.
Asıl güç cross coverage'tadır: cx_opcode_a, cx_opcode_b ve cx_opcode_flags ile işlem-operand ve işlem-bayrak kombinasyonları ölçülür. Anlamsız kombinasyonlar (ignore_bins) kapsam dışı bırakılır.
Kaynak Kod
// =============================================================================
// GUN 7 - Konu 5: Covergroup - Fonksiyonel Kapsam Tanimlari
// =============================================================================
class ALU_Coverage;
covergroup alu_cg with function sample(
ALU_Transaction::opcode_e opcode,
logic [7:0] a, logic [7:0] b,
logic [15:0] result, logic [3:0] flags
);
option.per_instance = 1;
// Islem kodu kapsami
cp_opcode: coverpoint opcode {
bins add = {ALU_Transaction::OP_ADD};
bins sub = {ALU_Transaction::OP_SUB};
bins and_op = {ALU_Transaction::OP_AND};
bins or_op = {ALU_Transaction::OP_OR};
bins xor_op = {ALU_Transaction::OP_XOR};
bins not_op = {ALU_Transaction::OP_NOT};
bins shl = {ALU_Transaction::OP_SHL};
bins shr = {ALU_Transaction::OP_SHR};
}
// Operand A kose durumlari
cp_op_a: coverpoint a {
bins zero = {0};
bins one = {1};
bins mid = {8'h7F, 8'h80};
bins max_minus_one = {8'hFE};
bins max = {8'hFF};
bins low = {[2:8'h7E]};
bins high = {[8'h81:8'hFD]};
}
// Operand B kose durumlari
cp_op_b: coverpoint b {
bins zero = {0};
bins one = {1};
bins mid = {8'h7F, 8'h80};
bins max_minus_one = {8'hFE};
bins max = {8'hFF};
bins low = {[2:8'h7E]};
bins high = {[8'h81:8'hFD]};
}
// Bayrak kapsami: [0]=Z, [1]=N, [2]=C, [3]=P (Ders 36-1 sozlesmesi)
// Her bayragin tek basina set oldugu durumlar + herhangi birinin set oldugu durumlar
cp_flags: coverpoint flags {
bins no_flags = {4'b0000};
bins zero_only = {4'b0001};
bins neg_only = {4'b0010};
bins carry_only = {4'b0100};
bins parity_only = {4'b1000};
wildcard bins zero_any = {4'b???1};
wildcard bins neg_any = {4'b??1?};
wildcard bins carry_any = {4'b?1??};
wildcard bins parity_any = {4'b1???};
}
// Sonuc araliklari
cp_result: coverpoint result {
bins zero_ = {0};
bins small_ = {[1:255]};
bins medium_ = {[256:65534]};
bins max_val = {65535};
}
// Cross coverage: Islem x Operand araliklari
cx_opcode_a: cross cp_opcode, cp_op_a;
cx_opcode_b: cross cp_opcode, cp_op_b;
// Mantiksal ve kaydirma islemlerinde carry daima 0'dir (DUT sozlesmesi);
// bu kombinasyonlar hedef degildir, kapsam hesabindan cikarilir.
cx_opcode_flags: cross cp_opcode, cp_flags {
ignore_bins no_carry_for_logic =
binsof(cp_opcode) intersect {ALU_Transaction::OP_AND, ALU_Transaction::OP_OR,
ALU_Transaction::OP_XOR, ALU_Transaction::OP_NOT,
ALU_Transaction::OP_SHL, ALU_Transaction::OP_SHR} &&
(binsof(cp_flags.carry_only) || binsof(cp_flags.carry_any));
}
endgroup
function new();
alu_cg = new();
endfunction
function void sample(ALU_Transaction txn);
alu_cg.sample(txn.opcode, txn.operand_a, txn.operand_b, txn.result, txn.flags);
endfunction
function void report();
$display("\n ========== KAPSAM RAPORU ==========");
$display(" Toplam Kapsam : %.1f%%", alu_cg.get_coverage());
$display(" cp_opcode : %.1f%%", alu_cg.cp_opcode.get_coverage());
$display(" cp_op_a : %.1f%%", alu_cg.cp_op_a.get_coverage());
$display(" cp_op_b : %.1f%%", alu_cg.cp_op_b.get_coverage());
$display(" cp_flags : %.1f%%", alu_cg.cp_flags.get_coverage());
$display(" cp_result : %.1f%%", alu_cg.cp_result.get_coverage());
$display(" =====================================");
endfunction
endclass
Kodun Açıklaması
covergroup alu_cg with function sample(...): Kapsam grubu, dışarıdan parametre alan birsamplefonksiyonuyla tanımlanır. Böylece örnekleme tetiklendiğindeopcode,a,b,result,flagsdeğerleri aktarılır.option.per_instance = 1her örnek için ayrı kapsam tutar.cp_opcode: Sekiz işlem kodunun her biri ayrıbins'e atanır (add,sub,and_op, ...).cp_op_a/cp_op_b: Operandlar köşe değerlere (zero,one,mid,max_minus_one,max) ve aralıklara (low,high) bölünür.cp_flags: İki tür bin vardır.*_onlybin'leri yalnızca tek bayrağın set olduğu desenleri (4'b0100= sadece carry) yakalar;wildcard bins *_anyise?joker karakteriyle "diğer bitler ne olursa olsun bu bayrak set" sorusunu yanıtlar (4'b?1??= carry set). Böylece hem saf hem karışık bayrak durumları ölçülür. Bit sırası DUT sözleşmesini izler:[0]=Z,[1]=N,[2]=C,[3]=P.cp_result: Sonuçzero_,small_,medium_,max_valaralıklarına ayrılır.- Cross'lar:
cx_opcode_avecx_opcode_b, işlem × operand kombinasyonlarını izler.cx_opcode_flags, mantıksal ve kaydırma işlemlerinde DUT'un carry'yi her zaman 0 ürettiğini bildiği için "AND× carry set" gibi asla oluşamayacak kombinasyonlarıignore_binsile hedef listesinden düşürür; aksi halde cross hiçbir zaman %100 olamazdı.binsof(cp_flags.carry_only)söz dizimi, bir coverpoint'in adlandırılmış bin'ine doğrudan atıf yapmanın yoludur. new(): Yapıcı,alu_cg = new()ile covergroup örneğini oluşturur (covergroup'lar açıkça örneklenmelidir).sample(ALU_Transaction txn): Transaction alanlarını ayırıpalu_cg.sample(...)'ı çağırır.report():get_coverage()ile toplam ve nokta bazlı kapsam yüzdelerini basar.
Önemli Noktalar
- Covergroup yapıcıda
new()ile örneklenmelidir; aksi haldesampleçağrıları kapsam toplamaz. ignore_binsile imkânsız kombinasyonların dışlanması kapsam hedefini gerçekçi tutar; AND/OR/XOR/NOT/SHL/SHR işlemlerinde carry sözleşme gereği hep 0 olduğundan "carry set" kombinasyonlarını hedeflemek, hiç dolmayacak bin'ler yaratırdı.- Cross coverage gerçek doğrulama gücüdür: Tekil noktalar %100 olsa bile, kombinasyonlar eksik kalabilir; cross bunu açığa çıkarır.
wildcard binskullanımı, bit maskeli kalıplarla (4'b???1) esnek bayrak yakalama sağlar.?karakteri hem0hem1ile eşleşir;x/zile de eşleştiği içinwildcardbin'lerXüreten bir DUT'ta yanlış dolabilir — scoreboard'daki===kontrolü bu yüzden ayrıca gereklidir.- Kapsam scoreboard tarafından
actual(gözlenen) değerlerle beslenir; bu, gerçekten DUT'a ulaşan senaryoların ölçülmesini garanti eder. - Bayrak isimleri DUT sözleşmesiyle eşleşir. Bu dersin önceki sürümünde
flags[3]içinovf_flag(overflow) adı kullanılıyordu; DUT bu bitte parity üretir. Yanlış isim kapsam yüzdesini değiştirmez ama raporu okuyan mühendisi yanıltır: "overflow %0 kapsanmış" diye gereksiz test yazdırabilirdi. Kapsam modeli de bir belgedir; isimler doğru olmalı.
Kapsam Modelini Okumak: Hangi Bin Boş Kalır?
Rastgele test (200 transaction) sonrasında tipik olarak dolmayan bin'ler ve nedenleri:
| Bin | Neden boş kalabilir? | Nasıl doldurulur? |
|---|---|---|
cp_op_a.max_minus_one (0xFE) |
c_corner_cases dağılımında özel ağırlığı yok, 1/254 ihtimal |
Köşe generator (corners dizisinde var) |
cp_result.max_val (0xFFFF) |
Yalnızca SUB ile a - b = -1 (ör. 0 - 1) üretir |
Yönlendirilmiş 0 - 1 testi |
cp_flags.neg_only |
N=1 ise SUB ile borrow var → C=1 de olur; saf "sadece N" çok nadir |
Belki imkânsız: ignore_bins adayı! |
cx_opcode_b × SHL/SHR × high/max |
c_shift_range operand_b'yi 0–7'ye sınırlar |
Bu kombinasyon kısıtla yasaklı → ignore_bins ile dışlanmalı |
Son iki satır kapsam mühendisliğinin özüdür: boş bir bin ya "daha fazla test yaz" ya da "bu kombinasyon imkânsız, modeli düzelt" demektir. Hangisi olduğuna karar vermek için DUT sözleşmesini ve kısıtları birlikte okumalısınız.
Benzetme: Kapsam modeli, bir haritadaki ziyaret edilecek yerler listesidir. Regresyon bittiğinde boş kalan yerler iki şey söyler: ya oraya gitmediniz (test ekle) ya da oraya gitmek zaten imkânsız (haritayı düzelt). Haritada olmayan bir yere ise asla gitmezsiniz; bu yüzden listeyi plan aşamasında, DUT'u görmeden yazmak en iyisidir.
Sık Yapılan Hatalar
- Bayrak bitlerine yanlış isim vermek: Yüzdeyi bozmaz ama raporu yanlış okutur.
- İmkânsız kombinasyonları
ignore_binsile dışlamamak: Cross hiçbir zaman %100 olmaz ve ekip "neden bitmiyor?" diye zaman kaybeder. illegal_bins'iignore_binsyerine kullanmak: "Carry mantıksal işlemde set" durumu DUT'ta oluşursa bu bir hatadır; aslındaillegal_binsdaha uygun olabilir — ama o zaman scoreboard ile iş bölümünü netleştirin: hata yakalama scoreboard'un, ölçme coverage'ın işidir. Bu projede yakalamayı scoreboard yapar (flagskarşılaştırması), coverage yalnızca ölçer.per_instanceolmadan birden fazla env örneği: İki environment aynı covergroup tipini kullanırsa kapsam birleşir;option.per_instance = 1ayrı tutar.- Kapsamı stimulus tarafında toplamak: Driver'ın gönderdiği ≠ DUT'un gördüğü. Bu projede scoreboard
actualile besler; doğru yer orasıdır.
Kendinizi Deneyin
Random_Test(200 txn) ileCorner_Test'i ayrı ayrı koşturupcp_op_a,cp_resultve cross yüzdelerini tabloya yazın. Hangi test hangi bin'leri doldurdu?cx_opcode_b'yeSHL/SHR×high/max_minus_one/maxkombinasyonlarını dışlayan birignore_binsekleyin. Cross yüzdesi ne oldu?cp_flags.neg_only'nin gerçekten imkânsız olup olmadığını araştırın:N=1ikenC=0veZ=0veP=0olan bir(opcode, a, b)var mı? (İpucu: yalnızcaSUBN=1üretebilir;0x00 - 0x01 = 0xFFFFiçinP'yi hesaplayın.)cp_result'abins eight_bit_max = {16'h00FF};ekleyin (8-bit'e tam sığan en büyük sonuç). Hangi işlemler bu bin'i doldurabilir?
Hızlı Kontrol: cx_opcode_flags'ta mantıksal işlemler için carry neden ignore_bins ile dışlanır?
DUT sözleşmesi gereği AND/OR/XOR/NOT/SHL/SHR işlemlerinde carry bayrağı her zaman 0'dır; "AND × carry set" kombinasyonu hiçbir doğru DUT'ta oluşmaz. Bu kombinasyonu hedefte tutmak cross'un %100'e ulaşmasını imkânsız kılar ve ekibi yanlış yönlendirir. ignore_bins onu hedef listesinden düşürür; DUT yine de carry üretirse bunu scoreboard'un bayrak karşılaştırması yakalar.