Assertions (SVA)
Gün 5: Arayüzler, Assertion ve Coverage | Immediate ve Concurrent assertion'lar, property, sequence
Bu derste SystemVerilog Assertions (SVA) ile tasarımın doğru davranıp davranmadığını otomatik olarak nasıl denetleyeceğimizi öğreneceğiz. immediate ve concurrent assertion farkını, sequence ve property yapılarını ve cover kullanımını ele alacağız.
Assertion Nedir, Neden Kullanılır?
Assertion, tasarımın uyması gereken bir kuralı biçimsel olarak ifade eden ve simülasyon sırasında sürekli denetleyen bir ifadedir. Kural ihlal edildiği anda assertion başarısız olur ve mesaj basar. Faydaları:
- Hatayı kaynağında yakalar: Hata, etkisi çıkışa yansımadan, oluştuğu saatte raporlanır.
- Belgeleme görevi görür: Protokol kuralları kodun içinde okunabilir biçimde yazılı durur.
- Kapsam ölçer:
coverile belirli senaryoların gerçekten test edildiğini doğrularsınız.
Immediate ve Concurrent Assertion Farkı
- Immediate assertion: Prosedürel bir blok içinde (
always,initial) yürütülür ve o anda, bir yazılımififadesi gibi anlık değerlendirilir. Zamansal davranış denetlemez. - Concurrent assertion: Bir saat olayına göre çalışır (
@(posedge clk)), birden fazla saat çevrimine yayılan zamansal ilişkileri kontrol eder.propertyvesequenceile kurulur.
Property, Sequence ve Operatörler
sequence: Zaman içindeki sinyal desenlerini tarif eder.##[1:3]"1 ila 3 çevrim sonra",[*4]"4 ardışık çevrim boyunca" anlamına gelir.property: Bir koşulun sonucunu tanımlar.|->(overlapping) tetikleme ile sonucu aynı çevrimde,|=>(non-overlapping) ise sonraki çevrimde bekler.disable iff (!rst_n): Reset aktifken assertion'ı devre dışı bırakır; reset sırasındaki sahte ihlalleri önler.$fell/$rose: Bir sinyalin düşen/yükselen kenarını yakalar.
Kaynak Kod
// =============================================================================
// GUN 5 - Konu 4: SystemVerilog Assertions (SVA) - Immediate ve Concurrent
// =============================================================================
module assertions;
logic clk = 0;
always #5 clk = ~clk;
logic rst_n;
logic req;
logic gnt;
logic valid;
logic ready;
logic [7:0] data;
logic error;
// Basit DUT davranisi
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
gnt <= 0;
ready <= 0;
error <= 0;
end else begin
gnt <= req; // 1 cycle gecikme ile grant
ready <= valid; // 1 cycle gecikme ile ready
error <= (data == 8'hFF); // 0xFF durumunda hata
end
end
// =========================================================================
// IMMEDIATE ASSERTIONS: Prosedurel blok icinde, aninda kontrol
// =========================================================================
always @(posedge clk) begin
if (rst_n) begin
// Basit immediate assertion: data'nin hicbir biti x/z olmamali
// (data !== 8'hxx yazmak yalnizca TUM bitler x ise yakalar; $isunknown her biti denetler)
assert_valid_data: assert (!$isunknown(data))
else $warning("[%0t] Data belirsiz (x/z)!", $time);
// Error ve valid ayni anda aktif olmamali
assert_no_error_valid: assert (!(error && valid))
else $error("[%0t] Error ve valid ayni anda aktif!", $time);
end
end
// =========================================================================
// SEQUENCE TANIMLARI: Zamansal davranislar icin yapi taslari
// =========================================================================
sequence s_handshake;
valid ##[1:3] ready;
endsequence
sequence s_burst;
valid [*4]; // 4 ardisik cycle boyunca valid
endsequence
// =========================================================================
// CONCURRENT ASSERTIONS: Zamansal iliskileri kontrol eder
// =========================================================================
// Property: req -> sonraki cycle gnt gelmeli
property p_req_gnt;
@(posedge clk) disable iff (!rst_n)
req |=> gnt;
endproperty
// Property: valid kalktiginda 1-3 cycle icinde ready gelmeli
property p_valid_ready;
@(posedge clk) disable iff (!rst_n)
valid |-> ##[1:3] ready;
endproperty
// Property: Reset durumunda tum cikislar sifir olmali
property p_reset_check;
@(posedge clk)
!rst_n |-> !gnt && !ready && !error;
endproperty
// Property: Req dustugunde sonraki cycle gnt de dusmeli
property p_req_deassert;
@(posedge clk) disable iff (!rst_n)
$fell(req) |=> $fell(gnt);
endproperty
// --- SEQUENCE KULLANAN YENI PROPERTY'LER ---
// s_handshake kullanan property: Handshake gerceklestiginde hata (error) olmamali
property p_handshake_no_error;
@(posedge clk) disable iff (!rst_n)
s_handshake |-> !error;
endproperty
// s_burst kullanan property: 4 valid'lik burst isleminden sonra gnt gelmeli
property p_burst_leads_to_gnt;
@(posedge clk) disable iff (!rst_n)
s_burst |-> ##[1:5] gnt;
endproperty
// =========================================================================
// ASSERTION'LARI ETKINLESTIRME (ASSERT & COVER)
// =========================================================================
assert property (p_req_gnt)
else $error("[%0t] REQ->GNT ihlali!", $time);
assert property (p_valid_ready)
else $error("[%0t] VALID->READY ihlali!", $time);
assert property (p_reset_check)
else $error("[%0t] Reset kontrol ihlali!", $time);
assert property (p_handshake_no_error)
else $error("[%0t] Handshake sequence sirasinda hata olustu!", $time);
assert property (p_burst_leads_to_gnt)
else $error("[%0t] Burst tamamlandi ancak grant gelmedi!", $time);
// Cover: Bu durumun gerceklestigini dogrula
cover property (p_req_gnt)
$display("[%0t] COVER: req->gnt gozlemlendi", $time);
// Sequence'larin gerceklesip gerceklesmedigini dogrudan takip etme
cover property (@(posedge clk) s_handshake)
$display("[%0t] COVER: Handshake sequence (s_handshake) tamamlandi", $time);
cover property (@(posedge clk) s_burst)
$display("[%0t] COVER: Burst sequence (s_burst) tamamlandi", $time);
// =========================================================================
// TEST UYARICILARI (STIMULUS)
// =========================================================================
initial begin
$display("=== SystemVerilog Assertions (SVA) ===\n");
rst_n = 0; req = 0; valid = 0; data = 0;
#20;
rst_n = 1;
#10;
// Normal req/gnt
$display("--- Normal REQ/GNT ---");
@(posedge clk); req = 1;
@(posedge clk); @(posedge clk);
req = 0;
#20;
// Valid/Ready handshake
$display("--- VALID/READY Handshake ---");
@(posedge clk); valid = 1; data = 8'hAB;
@(posedge clk); @(posedge clk);
valid = 0;
#30;
// Hata durumu
$display("--- Hata Testi (data=0xFF) ---");
@(posedge clk); valid = 1; data = 8'hFF;
@(posedge clk); valid = 0; data = 0;
#30;
// YENI: Burst durumu
$display("--- Burst Testi (4 ardisik valid) ---");
@(posedge clk);
req = 1; // p_burst_leads_to_gnt property'sini saglamak icin req tetikleniyor
valid = 1; data = 8'h11;
@(posedge clk); valid = 1; data = 8'h22; req = 0;
@(posedge clk); valid = 1; data = 8'h33;
@(posedge clk); valid = 1; data = 8'h44;
@(posedge clk); valid = 0;
#40;
$display("\n=== SVA Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
- DUT davranışı: İlk
always @(posedge clk or negedge rst_n)bloğu basit bir tasarımı modeller:gnt <= req(1 çevrim gecikmeli grant),ready <= valid(1 çevrim gecikmeli ready) veerror <= (data == 8'hFF)(0xFF'te hata). - Immediate assertion'lar:
assert_valid_data,$isunknown(data)iledata'nın herhangi bir bitininx/zolmadığını anlık kontrol eder ve ihlalde$warningüretir. (data !== 8'hxxyazımı yalnızca sekiz bitin tamamıxolduğunda yakalardı; tek biti belirsiz bir veri gözden kaçardı.)assert_no_error_valid,errorilevalid'in aynı anda aktif olmadığını denetler, ihlalde$errorverir. sequence s_handshake:valid ##[1:3] ready—valid'ten 1-3 çevrim sonrareadygelmesini tarif eder.sequence s_burst:valid [*4]—valid'in 4 ardışık çevrim sürdüğü deseni tanımlar.- Concurrent property'ler:
p_req_gnt:req |=> gnt—req'ten bir sonraki çevrimdegntgelmeli.p_valid_ready:valid |-> ##[1:3] ready—valid'ten sonra 1-3 çevrim içindereadygelmeli.p_reset_check:!rst_n |-> !gnt && !ready && !error— reset sırasında tüm çıkışlar sıfır olmalı (burada bilinçli olarakdisable iffyoktur).p_req_deassert:$fell(req) |=> $fell(gnt)—reqdüştüğünde sonraki çevrimdegntde düşmeli.p_handshake_no_error:s_handshake |-> !error— el sıkışma tamamlandığında hata olmamalı.p_burst_leads_to_gnt:s_burst |-> ##[1:5] gnt— 4'lük burst sonrası 1-5 çevrim içindegntgelmeli.
- Etkinleştirme: Her property
assert property (...) else $error(...)ile denetlenir. Ayrıcacover property (...)ifadeleri (p_req_gnt,s_handshake,s_burst) ilgili senaryonun gerçekten oluştuğunu raporlar. - Stimulus (
initialbloğu): Reset uygulanır; sırasıyla normalreq/gnt,valid/readyel sıkışma,data=0xFFhata senaryosu ve 4 ardışıkvalid'lik burst testleri yürütülür. Burst testindereqbilinçli tetiklenir, çünküp_burst_leads_to_gntgntüretimini gerektirir.
Önemli Noktalar
|->ve|=>ayrımı:|->sonucu aynı çevrimde,|=>ise bir sonraki çevrimde bekler. Yanlış seçim, doğru tasarımı bile başarısız assertion ile raporlatır.disable iffile reset koruması: Reset sırasında çıkışlar geçersizdir;disable iff (!rst_n)olmadan reset her assertion'ı sahte şekilde tetikleyebilir. Dikkat:p_reset_checkbilerek bu korumayı kullanmaz, çünkü amacı tam da reset davranışını doğrulamaktır.coverile boş test tuzağından kaçının: Bir assertion'ın hiç ihlal edilmemesi, senaryonun test edildiği anlamına gelmez.cover propertysenaryonun gerçekten gerçekleştiğini kanıtlar.- Sequence'ler yeniden kullanılır:
s_handshakeves_burstbirden çok property içinde tekrar kullanılır; bu, bakımı kolaylaştırır. - Immediate vs concurrent yerleşimi: Immediate assertion'lar prosedürel blok içinde anlık; concurrent assertion'lar modül düzeyinde saat tabanlı çalışır. İhtiyaca göre doğru türü seçin.
- Assertion'lar da örneklemeyi Preponed bölgede yapar: Concurrent assertion'lar sinyalleri saat kenarından hemen önceki değerleriyle (clocking block'un
#1stepgirişi gibi) okur. Bu yüzdenalways @(posedge clk)içinde<=ile güncellenen bir sinyal, assertion tarafından bir sonraki kenarda görülür.req |=> gntifadesinin "bir çevrim sonra" demesi tam da DUT'un bu NBA gecikmesine karşılık gelir. - Hata mesajlarında
$sampledve$past: Action block içinde$sampled(sig)örneklenen değeri,$past(sig, n)isençevrim önceki değeri verir; hata ayıklamada "ihlal anında ne vardı?" sorusunu yanıtlar. - Bu örnekte
assert_no_error_validihlali beklenir: Hata testindedata=0xFFilevalid=1aynı anda sürülür; bir çevrim sonraerror=1olur vevalidhâlâ 1'dir. Bu bilinçli bir "tasarım hatası" sahnesidir;$errormesajını görmek assertion'ın çalıştığının kanıtıdır.
SVA Operatörleri Hızlı Referans
| Operatör / yapı | Anlamı | Örnek |
|---|---|---|
##n |
n çevrim sonra |
a ##2 b → a, iki çevrim sonra b |
##[m:n] |
m ile n çevrim arasında | valid ##[1:3] ready |
##[1:$] |
1 veya daha fazla çevrim sonra (sonsuz üst sınır) | req ##[1:$] gnt |
[*n] |
n ardışık çevrim tekrar |
valid [*4] |
[*m:n] |
m–n arası ardışık tekrar | busy [*1:5] |
[->n] |
Ardışık olmayan, n. kez gerçekleşme (goto) |
ack [->3] → 3. ack |
[=n] |
n kez gerçekleşme, sonrasında serbest |
req [=2] |
|-> |
Örtüşen implication (aynı çevrim) | req |-> gnt |
|=> |
Örtüşmeyen implication (sonraki çevrim) | req |=> gnt |
$rose(s) / $fell(s) |
Yükselen / düşen kenar | $rose(req) |
$stable(s) / $changed(s) |
Değişmedi / değişti | $stable(addr) |
$past(s, n) |
n çevrim önceki değer | $past(data) == data |
disable iff (c) |
c doğruyken denetimi kapat |
disable iff (!rst_n) |
throughout |
Sol taraf, sağ taraf boyunca doğru kalsın | !rst_n throughout (a ##1 b) |
s1 and s2 / s1 or s2 |
İki sequence'in ikisi de / biri | — |
s1 intersect s2 |
Aynı anda başlayıp aynı anda biten | — |
first_match(s) |
Çoklu eşleşmenin ilkini al | first_match(a ##[1:3] b) |
Benzetme: Assertion, tasarımın yanına oturttuğunuz yorulmaz bir denetçidir. Her saat kenarında defterine bakar: "
reqgeldi, bir çevrim sonragntgeldi mi?" Gelmezse anında düdük çalar. Siz dalga formunda saatlerce aramazsınız; denetçi ihlalin hangi çevrimde olduğunu söyler.coverise denetçinin "bu senaryo gerçekten yaşandı" diye attığı tiktir.
assert, assume, cover, expect
| Anahtar kelime | Ne yapar? | Nerede? |
|---|---|---|
assert property |
Kuralı denetler, ihlalde hata | Her yerde (simülasyon + formal) |
assume property |
Girişlerin bu kurala uyduğunu varsayar | Formal doğrulamada çevre kısıtı; simülasyonda assert gibi davranır |
cover property |
Senaryonun gerçekleştiğini sayar | Kapsam ölçümü |
expect |
Prosedürel kod içinde bir property'nin gerçekleşmesini bekler | Testbench task'larında: expect (@(posedge clk) ##[1:5] done) else $error(...) |
Sık Yapılan Hatalar
|->ile|=>'yi karıştırmak:req |-> gntaynı çevrimdegntister; DUT bir çevrim gecikmeli üretiyorsa doğru tasarım hatalı raporlanır.disable iffunutmak: Reset sırasında çıkışlar geçersizdir; assertion sahte ihlal üretir. Reset davranışını test eden property hariç, hepsinde kullanın.- Sonsuz üst sınırlı sequence'leri kontrolsüz bırakmak:
req |-> ##[1:$] gntifadesignthiç gelmezse asla başarısız olmaz (simülasyon biter, assertion "bekliyor" kalır). Üst sınırı makul bir sayıyla (##[1:100]) sınırlayın. xkontrolünü!== 8'hxxile yapmak: Yalnızca tüm bitlerxise yakalar.$isunknown()kullanın.- Immediate assertion'ı
initialdışında saat olmadan yazmak: Kombinasyonel biralways_combiçinde immediate assertion, sinyal geçişleri sırasında (glitch) sahte tetiklenebilir. Zamanlı kontroller için concurrent assertion seçin. coveryazmamak: Hiç ihlal edilmeyen bir assertion, senaryonun hiç oluşmadığı anlamına da gelebilir. Her kritik property için bircoverekleyin.
Kendinizi Deneyin
p_req_gnt'yireq |-> gntyapın (örtüşen). Hangi testlerde ihlal aldınız? DUT'un 1 çevrimlik gecikmesiyle ilişkilendirin.p_valid_ready'dendisable iff (!rst_n)ifadesini silin ve reset sırasında sahte ihlal görünüp görünmediğini kontrol edin (ipucu:validreset sırasında 0 olduğu için belki görünmez;valid=1iken reset uygulayıp tekrar deneyin).property p_data_stable; @(posedge clk) disable iff (!rst_n) valid && !ready |=> $stable(data); endpropertyekleyin: "ready gelmedendatadeğişmemeli". Stimulus'tadata'yı erken değiştirerek ihlali tetikleyin.cover property (@(posedge clk) req ##1 gnt ##1 !gnt)ekleyin ve kaç kez gerçekleştiğini sayın.[->n]operatörünü kullanarak "üçüncügnt" anını yakalayan bir cover yazın.
Hızlı Kontrol: a |-> b ile a |=> b arasındaki fark nedir?
|-> (örtüşen): a doğru olduğu aynı çevrimde b de doğru olmalı. |=> (örtüşmeyen): a doğruysa b bir sonraki çevrimde doğru olmalı; a |=> b, a |-> ##1 b ile eşdeğerdir. DUT çıkışları genelde <= ile bir çevrim gecikmeli üretildiği için istek→yanıt kurallarında çoğunlukla |=> kullanılır.