0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

sva_assertion: 15道助力飛升的斷言練習(xí)

路科驗(yàn)證 ? 來源:路科驗(yàn)證 ? 2023-12-08 16:26 ? 次閱讀

前言

紙上得來終覺淺,絕知此事要躬行。把之前學(xué)習(xí)到的15道并行斷言練習(xí)整理好拿出來助大家一同飛升,相信我,練完之后再也沒有難得住你的斷言了,你就信吧!每道題都遵循著題目-解析-答案-驗(yàn)證四個(gè)步驟進(jìn)行,除非太簡單了可能會(huì)省去解析或者驗(yàn)證的過程。

省流版在最后,直接看最后一題!

練習(xí)1

題目

系統(tǒng)復(fù)位后,狀態(tài)機(jī)信號(hào)status在任意一拍均有且只有1bit信號(hào)有效。

分析

每一拍都要檢查,因此不需要前置蘊(yùn)含算子了(蘊(yùn)含算子即|->和|=>);均有且只有1比特信號(hào)有效意味著我們需要使用系統(tǒng)函數(shù)$onehot();復(fù)位之后檢查我們需要用到disable iff語句;

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        $onehot(status);
endproperty
assert_test: assert property(assert_chk); //這行之后就省略了哈

驗(yàn)證

注意嗷,對(duì)于onehot函數(shù),status全0也是不行的哈。

12ef3442-958e-11ee-8b88-92fbcf53809c.png
"/home/ICer/test.sv", 484: testbench.u_test.assert_test: started at 335000ps failed at 335000ps
Offending '$onehot(status)'
"/home/ICer/test.sv", 484: testbench.u_test.assert_test: started at 345000ps failed at 345000ps
Offending '$onehot(status)'
$finish called from file "../top/testbench.sv", line 35.

練習(xí)2

題目

系統(tǒng)復(fù)位后,data信號(hào)在任何時(shí)刻均不能為X態(tài)或Z態(tài)。

分析

和上一個(gè)題目類似,可以直接調(diào)用系統(tǒng)函數(shù),注意是不能為X態(tài)或Z態(tài)。

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        ~$isunkonwn(data);
endproperty

太簡單了,就不進(jìn)行仿真確認(rèn)了哈。

練習(xí)3

題目

某一奇怪的握手協(xié)議中規(guī)定,vld信號(hào)只能在ready信號(hào)有效期間有效。

分析

簡單來說可以反向思考,其實(shí)就是任何一拍vld是有效的,那么ready信號(hào)也必須是有效的,因此我們可以使用蘊(yùn)含算子|->在vld有效時(shí)候檢查ready是否為有效態(tài)。

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        vld |-> ready;
endproperty

練習(xí)4

題目

接口data_vld有效時(shí),data信號(hào)值必須處于合理的范圍內(nèi)(假設(shè)合理范圍時(shí)‘h0000~'h7FFF)。

分析

data信號(hào)值處于合理范圍需要用到inside方法,他本身就是檢查一個(gè)值是否處于之后的范圍內(nèi)。

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        data_vld |-> (data inside{['h0:'h7FFF]});
endproperty

驗(yàn)證

12fbf240-958e-11ee-8b88-92fbcf53809c.png
"/home/ICer/test.sv", 490: testbench.u_test.assert_test: started at 505000ps failed at 505000ps
Offending '(data inside {['b0:'h00007fff]})'
"/home/ICer/test.sv", 490: testbench.u_test.assert_test: started at 515000ps failed at 515000ps
Offending '(data inside {['b0:'h00007fff]})'
$finish called from file "../top/testbench.sv", line 35.

練習(xí)5

題目

data_vld是一個(gè)檢測上升沿的單拍脈沖信號(hào),最多有效1拍就會(huì)拉低等待下次觸發(fā)。

分析

其實(shí)就是說data_vld如果這一拍為1,那么下一拍一定為0,那么我們只需要在data_vld==1時(shí)檢查下一拍是不是0就可以了,可以使用|=>也可以使用|-> ##1。

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        data_vld |=> ~data_vld;
endproperty

練習(xí)6

題目

單比特信號(hào)data_vld連續(xù)有效時(shí)間跨度最多為5拍。

分析

要檢查vld信號(hào)每次為1應(yīng)該持續(xù)[1:5]拍,想想什么操作符是連續(xù)持續(xù)n拍呢?a[*n]:連續(xù)重復(fù)運(yùn)算符,a[*2:4]含義為a信號(hào)重復(fù)2~4拍。不如我們先寫一個(gè)簡單的,如果規(guī)定vld有效必須為5拍,那么我們?cè)趺磳懩兀窟@里肯定要用到$rose和$fell函數(shù)了,因?yàn)槌掷m(xù)幾拍肯定是從頭數(shù)到尾我們需要上升沿和下降沿;持續(xù)幾拍那就用到了我們連續(xù)重復(fù)了[*m:n],那我們先寫一個(gè)看看:

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        $rose(data_vld) |-> data_vld[*5] ##0 $fell(data_vld);
endproperty

看上去挺合理的,data_vld有效開始檢查,到data_vld無效時(shí)結(jié)束,在這期間data_vld連續(xù)有效了5拍,如果不是5拍就報(bào)錯(cuò)。不過這樣寫是有問題的,問題請(qǐng)見下面的波形,這很明顯是一個(gè)維持了5拍的信號(hào)對(duì)吧:

130710f8-958e-11ee-8b88-92fbcf53809c.jpg

注意開始檢查的時(shí)刻是60ns,此時(shí)data_vld采樣值為1與上一拍0滿足了$rose,同時(shí)由于我們使用了|->符號(hào)單拍開始檢查,所以data_vld在60ns出重復(fù)為1次;接下來80ns處連續(xù)重復(fù)了第2次,100ns處重復(fù)第3次,120ns處重復(fù)第4次,140ns處重復(fù)第5次,好的在140ns處data_vld[*5]匹配完成;接下來匹配##0 $fell(data_vld),##0含義為當(dāng)拍就要看,那么當(dāng)拍data_vld值為1上一拍也是1,$fell匹配失敗,斷言也就失敗了。

因此這樣的寫法是不正確的,會(huì)把一個(gè)符合預(yù)期的行為誤判為斷言失敗,所以我們修改一下成下面這樣:

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        $rose(data_vld) |-> data_vld[*5] ##1 $fell(data_vld);
endproperty

變成##1就好啦,在data_vld[*5]的下一拍來檢查$fell,完美的解決了這個(gè)問題,這個(gè)用法一定要牢記。

再來思考一個(gè)問題,如果不用$rose(data_vld) |-> data_vld[*5] ##1 $fell(data_vld)而改成data_vld |-> data_vld[*5] ##1 $fell(data_vld)會(huì)有什么后果,反正都是再data_vld有效時(shí)候開始檢查嘛;后果就是本來只在60ns處開始一條檢查線程,現(xiàn)在會(huì)在60ns、80ns、100ns、120ns和140ns處開了多條檢查線程,而后面這些線程顯然是一定失敗的也不是我們需要檢查的。

那么回到題目本身,其實(shí)也就很好解決了,只需要把[*5]修改為[*1:5]就契合了題目要求。

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        $rose(data_vld) |-> data_vld[*1:5] ##1 $fell(data_vld);
endproperty

驗(yàn)證

data_vld分別持續(xù)了5拍、4拍、6拍的波形:

130c9a3c-958e-11ee-8b88-92fbcf53809c.png
assert pass case!!!
assert pass case!!!
"/home/ICer/test.sv", 488: testbench.u_test.assert_test: started at 995000ps failed at 1045000ps
Offending '$fell(data_vld)'
assert fail case!!!
$finish called from file "../top/testbench.sv", line 35.

練習(xí)7

題目

req信號(hào)(單拍脈沖)有效之后(含當(dāng)拍),rsp信號(hào)有效之前(含當(dāng)拍),必須要收到(出現(xiàn))4次data_vld有效。

分析

這個(gè)題目和上一個(gè)題有點(diǎn)類似,我們來分析一下。這個(gè)斷言應(yīng)該在req有效當(dāng)拍開始而在rsp有效(第一次有效)時(shí)結(jié)束,我們關(guān)注的就是req->rsp之間的事情。所以很顯然前置算子就是req(因?yàn)槭菃闻男盘?hào),所以不需要用$rose)。后面怎么寫呢?我們可以使用intersect + [->1]的句式,a [->n]:非連續(xù)跟隨重復(fù)符,或者叫g(shù)o-to重復(fù)符,含義是a非連續(xù)(就是無所謂連不連續(xù))重復(fù)n次,只在第n次重復(fù)時(shí)刻點(diǎn)匹配(跟隨的含義)。最常用的a [->1]等價(jià)于(!a) [*0:$] ##1 a,也就是匹配了a序列第一次成立的時(shí)刻。

intersect運(yùn)算符是最重要的一個(gè)運(yùn)算符,intersect和and有一些類似,都是連接兩個(gè)事件,兩個(gè)事件均成功整個(gè)匹配才成功。不過intersect多了一個(gè)條件,那就是兩個(gè)事件必須在同一時(shí)刻結(jié)束。換句話說a intersect b能匹配成功,a、b兩個(gè)序列的長度必須相等。

先把答案寫下來,再分析下:

property vld_chk;
    @(posedge clk) disable iff(~rst_n)
        req |-> data_vld[=4] intersect (rsp[->1]);
endproperty

intesect連接的兩個(gè)序列必須等長,那么后面的ack[->1]持續(xù)的時(shí)間段時(shí)哪里呢?從下圖的波形中可以看出時(shí)從前置算子匹配成功的60ns到ack信號(hào)第一次為高有效的220ns處;因此通過這樣的句式就成功的限制住了data_vld高有效4次這一事件必須也發(fā)生在60ns~220ns之間,即從req有效當(dāng)拍到ack有效當(dāng)拍;這個(gè)句式事實(shí)上時(shí)非常常見的寫法。

131cbde0-958e-11ee-8b88-92fbcf53809c.png

答案

property vld_chk;
    @(posedge clk) disable iff(~rst_n)
        req |-> data_vld[=4] intersect (rsp[->1]);
endproperty

驗(yàn)證

第一段成功了,第二段是斷言失敗。

132a88ee-958e-11ee-8b88-92fbcf53809c.png
assert pass case!!!
"/home/ICer/test.sv", 488: testbench.u_test.assert_test: started at 955000ps failed at 1005000ps
Offending 'data_vld'
assert fail case!!!
$finish called from file "../top/testbench.sv", line 35.

練習(xí)8

題目

req信號(hào)(單拍脈沖)有效之后(不含當(dāng)拍從下一拍開始),rsp信號(hào)有效之前(不含當(dāng)拍,rsp有效之前),必須要收到(出現(xiàn))4次data_vld有效。

分析

和上一個(gè)問題非常相似,我們繼續(xù)來解決一下,其實(shí)核心好事data_vld[=4]這個(gè)序列發(fā)生在哪個(gè)時(shí)間段的問題。req的下一拍開始,那么我們可以使用|=>或者|->##1,這兩個(gè)是都可以的;ack有效的前一拍data_vld[=4]要匹配完成,要怎么處理呢?可以采用這種形式(data_vld[=4] ##1 1'b1),由于1'b1是一個(gè)恒成立的序列,這樣寫的效果就是data_vld[=4]匹配成功點(diǎn)往后推遲了一拍。

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        req |-> ##1 (data_vld[=4] ##1 1'b1) intersect (rsp[->1]);
endproperty

我們還是以波形來理解,先看一個(gè)成功的波形。前置算子req在60ns匹配成功,|-> ##1意味著從下一拍開始進(jìn)行后續(xù)的判定。黃色箭頭220ns處rsp[->1]匹配成功,這意味著(data_vld[=4] ##1 1'b1)序列必須在80ns~220ns間匹配完成,而在data_vld[=4]在200ns藍(lán)色箭頭處匹配成功,因此(data_vld[=4] ##1 1'b1)在220ns匹配成功,斷言成功。

13351ade-958e-11ee-8b88-92fbcf53809c.jpg

下面看一個(gè)失敗的例子,rsp[->1]在220ns匹配成功,而(data_vld[=4] ##1 1'b1)在哪里匹配成功呢?在240ns處才匹配成功(換句話說,在220ns處剛剛匹配到data_vld[=3] ##1 1'b1成功),因此最后斷言失敗。

134603a8-958e-11ee-8b88-92fbcf53809c.jpg

再看一個(gè)略帶迷惑性的例子,如下圖這個(gè)行為最后斷言是會(huì)報(bào)成功還是失敗呢?我和同學(xué)有一些爭論,不過我認(rèn)為是會(huì)成功的,因?yàn)樵?20ns時(shí)(data_vld[=4] ##1 1'b1)報(bào)匹配成功,rsp[->1]在220ns處報(bào)匹配成功,intersect前后序列等長斷言匹配成功,檢查也就此結(jié)束。不過你說在220ns處data_vld[=5]了,那沒關(guān)系因?yàn)椋╠ata_vld[=5] ##1 1'b1)作為一個(gè)整體在240ns才匹配此時(shí)我的斷言都已經(jīng)檢查完成了,等待下一次req有效才會(huì)開始下一次檢查,因此對(duì)斷言成功沒有影響。

1353ad96-958e-11ee-8b88-92fbcf53809c.jpg

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        req |-> ##1 (data_vld[=4] ##1 1'b1) intersect (rsp[->1]);
endproperty

驗(yàn)證

四段波形,分別是成功,失敗,失敗,成功。

135dd1a4-958e-11ee-8b88-92fbcf53809c.png
assert pass case!!!
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 665000ps failed at 805000ps
Offending 'rsp'
assert fail case!!!
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 915000ps failed at 965000ps
Offending 'rsp'
assert fail case!!!
assert pass case!!!
$finish called from file "../top/testbench.sv", line 35.

練習(xí)9

題目

上一個(gè)題的變種,稍有變化。n_ready是維持信號(hào),在n_ready有效期間,data_vld信號(hào)有效的次數(shù)應(yīng)該小于等于4次,data_vld信號(hào)為離散信號(hào)。

分析

這也是實(shí)際中很常見的場景,當(dāng)后級(jí)模塊的n_ready信號(hào)拉起時(shí),一般表示后級(jí)模塊已經(jīng)不能接收更過的數(shù)據(jù)了,這個(gè)時(shí)候作為前級(jí)模塊應(yīng)該盡快停止數(shù)據(jù)的發(fā)送,不過鑒于前級(jí)模塊一般需要一些反應(yīng)的時(shí)間因此后級(jí)模塊允許再發(fā)送幾個(gè)數(shù)據(jù)過去(所謂的過沖),在本題目中這個(gè)數(shù)量最大為4個(gè),也就是說0~4個(gè)都是可以接收的。

注意n_ready是維持信號(hào),因此我們選取前置算子時(shí)候要選取的是n_ready的上升沿$rose(n_ready);我們?nèi)耘f選擇intersect+[->1]的組織形式,那么后面跟的應(yīng)該是!n_ready[->1]即檢查結(jié)束點(diǎn)為n_ready無效的時(shí)刻,因此也可以寫成$fell(n_ready)[->1],[->1]這個(gè)意思就是第一次成功的意思哈。初步組織斷言為:

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        $rose(n_ready) |-> (data_vld[=0:4]) intersect ($fell(n_ready)[->1]);
endproperty

不過還是老問題,這樣寫會(huì)發(fā)生誤判下面這種情況,可以看到下圖中n_ready有效期間data_vld有效了4拍這是完全符合要求的,不過會(huì)被上面斷言誤判為失敗,原因還是在于intersect后面的$fell(n_ready)是在220ns處匹配完成匹配的而不是200ns,因此220ns處的data_vld有效也會(huì)被計(jì)入因此斷言會(huì)判定data_vld[=5],導(dǎo)致斷言失敗。

要避免這一個(gè)問題還是要用到上個(gè)練習(xí)的方法,引入##1 1'b1(還是直接理解成把序列匹配的時(shí)間點(diǎn)往后推一拍),這樣在220ns處(data_vld[0:4] ##1 1'b1)處于匹配成功的時(shí)間點(diǎn),整個(gè)斷言判定成功。220ns處的data_vld就被這個(gè)##1 1'b1給推出去了。

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        $rose(n_ready) |-> (data_vld[=0:4] ##1 1'b1) intersect ($fell(n_ready)[->1]);
endproperty

驗(yàn)證

13686e5c-958e-11ee-8b88-92fbcf53809c.png
assert pass case!!!
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 565000ps failed at 725000ps
Offending '$fell(n_ready)'
assert fail case!!!
$finish called from file "../top/testbench.sv", line 35.

練習(xí)10

題目

req信號(hào)(單拍脈沖信號(hào))有效之后,rsp信號(hào)(單拍脈沖信號(hào))有效之前(含當(dāng)拍),req信號(hào)不能再次有效,如下圖為合理情況的波形:

137299a4-958e-11ee-8b88-92fbcf53809c.jpg

分析

這其實(shí)也是系統(tǒng)中比較常見的一個(gè)場景,那么我們來組織一下斷言;從前置算子入手,因?yàn)檎f了req是單拍脈沖信號(hào)所以前置算子可以直接寫req了;后面要斷的是什么呢?是在rsp[->1]之前req不能為1,所以可以使用intersect (rsp[->1])句式,寫成~req intersect (rsp[->1]);我們觀察下intersect前面是一個(gè)信號(hào)表達(dá)式,那么就跟前面我寫的東西連上了,這里也可以用throughout來連接等長的表達(dá)式與序列;而要使用|->還是|=>來連接呢?必須使用|=>來連接的,因?yàn)槟銖牟荒茉趓eq有效的當(dāng)拍斷言檢查req無效吧?

答案

property assert_chk;
    @(posedge clk) disable iff(~rst_n)
        req |=> ~req throughout (rsp[->1]);
endproperty

驗(yàn)證

138c9142-958e-11ee-8b88-92fbcf53809c.png
assert pass case!!!
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 485000ps failed at 535000ps
Offending '(~req)'
assert fail case!!!
$finish called from file "../top/testbench.sv", line 35.

練習(xí)11

題目

某個(gè)模塊接收前級(jí)模塊發(fā)送的請(qǐng)求req,請(qǐng)求以req_id作為標(biāo)記,本模塊以rep和rep_id作為響應(yīng)信號(hào)表示已經(jīng)接收到請(qǐng)求;請(qǐng)檢查req和req_id有效后,最近的一拍rsp有效時(shí)rsp_id等于req_id。

1397727e-958e-11ee-8b88-92fbcf53809c.jpg

分析

這個(gè)問題中遇到一個(gè)難點(diǎn),就是我要判斷rsp_id是不是跟上一個(gè)req_id一樣,那么我就必須想辦法把reg_id保存下來;SVA提供了這樣的方法,我們直接用就可以了,我們可以在斷言中定義局部變量用來保存數(shù)據(jù)以備之后檢查使用,注意這個(gè)局部變量只在斷言期間有效,無法在斷言外使用。

確定一下前置算子,在什么情況下我們需要檢查呢,就是在req有效后最近的那一拍rsp有效時(shí),我們需要觸發(fā)斷言檢查,“最近的那一拍”自然就時(shí)req后rsp第一次為1的時(shí)間點(diǎn),因此使用req ##1 rsp[->1]來尋找這個(gè)時(shí)間點(diǎn)(這里我默認(rèn)rsp至少比req晚一拍),前置算子有了自然就可以完整的組織斷言,注意解答中的tmp_id就是斷言中可以使用的臨時(shí)變量。

答案

property assert_chk;
    reg [3:0] tmp_id;
    @(posedge clk) disable iff(~rst_n)
        (req,tmp_id = req_id) ##1 (rsp[->1]) |-> (rsp_id == tmp_id);
endproperty

驗(yàn)證

13a74d52-958e-11ee-8b88-92fbcf53809c.png
assert pass case!!!
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 655000ps failed at 765000ps
Offending '(rsp_id == tmp_id)'
assert fail case!!!
$finish called from file "../top/testbench.sv", line 35.

練習(xí)12

題目

某個(gè)模塊接收前級(jí)模塊發(fā)送的請(qǐng)求req,請(qǐng)求以req_id作為標(biāo)記,本模塊以rep和rep_id作為響應(yīng)信號(hào)表示已經(jīng)接收到請(qǐng)求;請(qǐng)檢查req有效后,下一次req有效時(shí)req_id為上一次req_id加1(0~FF~0循環(huán)發(fā)送id)。

13b1df7e-958e-11ee-8b88-92fbcf53809c.jpg

分析

跟上一個(gè)題目幾乎是一毛一樣的,直接解答就好了。

答案

property assert_chk;
    reg [7:0] tmp_id
    @(posedge clk) disable iff(~rst_n)
        (req,tmp_id = req_id) ##1 (req[->1]) |-> (req_id == tmp_id+1);
endproperty

練習(xí)13

題目

某個(gè)模塊接收前級(jí)模塊發(fā)送的請(qǐng)求req,請(qǐng)求以req_id作為標(biāo)記,本模塊以rep和rep_id作為響應(yīng)信號(hào)表示已經(jīng)接收到請(qǐng)求;某個(gè)id被本模塊相應(yīng)前,不應(yīng)該再收到相同id的req請(qǐng)求。

13c19770-958e-11ee-8b88-92fbcf53809c.jpg

分析

不用分析,使用intersect或者throughout都可以。

答案

property assert_chk;
    reg [7:0] tmp_id
    @(posedge clk) disable iff(~rst_n)
        (req,tmp_id = req_id) |=> ~(req && req_id==tmp_id) throughout (rsp && rsp_id==tmp_id)[->1];
endproperty

驗(yàn)證

4'hB的req還沒回,又發(fā)過來一個(gè)同樣id的請(qǐng)求,報(bào)錯(cuò)了。

13c9097e-958e-11ee-8b88-92fbcf53809c.png
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 405000ps failed at 475000ps
Offending '(~(req && (req_id == tmp_id)))'
$finish called from file "../top/testbench.sv", line 35.

練習(xí)14

題目

某模塊與兩個(gè)前級(jí)模塊對(duì)接,前級(jí)模塊1發(fā)送請(qǐng)求req1和req1_id,前級(jí)模塊2發(fā)送請(qǐng)求req2和req2_id,當(dāng)該模塊在同一拍收到兩個(gè)前級(jí)模塊的請(qǐng)求且req_id一致時(shí),需要保證首先對(duì)前級(jí)模塊1進(jìn)行響應(yīng)。

13ccdce8-958e-11ee-8b88-92fbcf53809c.jpg

分析

直接解答吧。

答案

property assert_chk;
    reg [7:0] tmp_id;
    @(posedge clk) disable iff(~rst_n)
        (req1 & req2 & req1_id==req2_id, tmp_id = req1_id) |=> ~(rsp2 && rsp2_id==tmp_id) throughout (rsp1 && rsp1_id==tmp_id)[->1];
endproperty

驗(yàn)證

13df1ed0-958e-11ee-8b88-92fbcf53809c.png
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 405000ps failed at 435000ps
Offending '(~(rsp2 && (rsp2_id == tmp_id)))'
$finish called from file "../top/testbench.sv", line 35.

練習(xí)15

題目

hazard(或者稱bypass)讀取。在對(duì)SDRAM進(jìn)行數(shù)據(jù)讀取,如果在第1拍發(fā)起讀操作,需要在第4拍得到讀取數(shù)據(jù);如果在這4拍內(nèi)有對(duì)相同地址的寫入操作,那么我們需要使用最新的寫入值作為讀操作的返回值(也就是常說的mem讀取hazard處理);舉例如下圖,60ns發(fā)起讀操作120ns返回?cái)?shù)據(jù)(均以上升沿實(shí)際采樣為準(zhǔn)),在這期間如果沒有對(duì)同一地址的寫入操作,那么將返回從sdram中讀取的數(shù)據(jù),如果有的話如下圖60ns和100ns時(shí)均有對(duì)同一地址的寫入操作,那么我們必然應(yīng)該回讀最新的寫入值即100ns時(shí)刻寫入的20;注意由于要求hazard 4拍,那么在60ns~120ns期間發(fā)生的同一地址寫操作均需要檢查進(jìn)去。

13ed73ae-958e-11ee-8b88-92fbcf53809c.jpg

分析

這個(gè)問題是我學(xué)到的最難的斷言了,看起來簡單做起來完全沒有思緒的那一種。直接來思考有點(diǎn)轉(zhuǎn)不過彎來,不如我們分四種場景來檢查先:對(duì)第0拍繼續(xù)hazard、對(duì)第1拍繼續(xù)hazard、對(duì)第2拍繼續(xù)hazard和對(duì)第3拍繼續(xù)hazard。

1.什么時(shí)候我們需要對(duì)第0拍繼續(xù)hazard呢?條件就是第0拍有對(duì)同一地址的寫入,且之后的3拍沒有同一地址的寫入,那么讀回?cái)?shù)據(jù)必須是第0拍寫入的數(shù)據(jù),波形示意如下:

13f10514-958e-11ee-8b88-92fbcf53809c.jpg

根據(jù)描述我們可以寫出斷言如下,結(jié)合波形具體做一下解釋;rd_en有效即對(duì)應(yīng)波形中的60ns時(shí)刻,由于只對(duì)同一地址進(jìn)行hazard因此我們需要記錄一下地址(當(dāng)拍的這種其實(shí)不記錄也行,主要為了和后面一致);##0表示當(dāng)拍,當(dāng)拍有wr_en&wr_addr=tmp_addr的話說明這個(gè)數(shù)據(jù)我們有可能進(jìn)行hazard所以也得保留下來;要繼續(xù)滿足什么條件呢,要滿足從下一拍開始連續(xù)3拍不能有wr_en&wr_addr=tmp_addr這個(gè)事出現(xiàn),否則我們就要hazard后面最新的一拍嘛,因此寫上##1 ~(wr_en & wr_addr==tmp_addr)[*3],注意因?yàn)?#1和[*3]的作用,時(shí)間點(diǎn)已經(jīng)來到了120ns;如果前置算子的條件滿足了,那么我們只需要在120ns當(dāng)拍檢查回讀數(shù)據(jù)rd_data==tmp_data是否成功就可以了,tmp_data就是我們之前記錄的第0拍的同一地址寫入數(shù)據(jù)嘛;好的因此第一種情況我們寫出來了,這個(gè)斷言是必須要滿足的。

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##0 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*3] |-> rd_data==tmp_data;
endproperty

2.什么時(shí)候我們需要對(duì)第1拍繼續(xù)hazard呢?條件就是第1拍有對(duì)同一地址的寫入(顯然第0拍有沒有已經(jīng)不重要了或者說不必關(guān)心了),且之后的2拍沒有同一地址的寫入,那么讀回?cái)?shù)據(jù)必須是第1拍寫入的數(shù)據(jù),波形示意如下:

13fc4906-958e-11ee-8b88-92fbcf53809c.jpg

rd_en有效即對(duì)應(yīng)波形中的60ns時(shí)刻,由于只對(duì)同一地址進(jìn)行hazard因此我們需要記錄一下地址,下一拍有wr_en&wr_addr=tmp_addr的話說明這個(gè)數(shù)據(jù)我們有可能進(jìn)行hazard所以保留下來;要繼續(xù)滿足從下一拍開始連續(xù)2拍不能有wr_en&wr_addr=tmp_addr這個(gè)事出現(xiàn),因此寫上##1 ~(wr_en & wr_addr==tmp_addr)[*2],時(shí)間點(diǎn)已經(jīng)來到了120ns;如果前置算子的條件滿足了,那么我們只需要在120ns當(dāng)拍檢查回讀數(shù)據(jù)rd_data==tmp_data是否成功就可以了,這個(gè)斷言是必須要滿足的。

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##1 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*2] |-> rd_data==tmp_data;
endproperty

3.什么時(shí)候我們需要對(duì)第2拍繼續(xù)hazard呢?條件就是第2拍有對(duì)同一地址的寫入(顯然第0、1拍有沒有已經(jīng)不重要了),且之后的1拍沒有同一地址的寫入,那么讀回?cái)?shù)據(jù)必須是第1拍寫入的數(shù)據(jù),波形示意如下:

1409a542-958e-11ee-8b88-92fbcf53809c.jpg

不多分析了,直接寫:

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##2 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*1] |-> rd_data==tmp_data;
endproperty

4.什么時(shí)候我們需要對(duì)第3拍繼續(xù)hazard呢?條件就是第3拍有對(duì)同一地址的寫入(不需要任何其他條件了)讀回?cái)?shù)據(jù)必須是第3拍寫入的數(shù)據(jù),波形示意如下:

1443365e-958e-11ee-8b88-92fbcf53809c.jpg

那么可以直接寫出斷言了:

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##3 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) |-> rd_data==tmp_data;
endproperty

我們觀察了一下,這個(gè)形式跟之前的好像有點(diǎn)不太和諧,沒關(guān)系可以修理一下,這里我們使用一個(gè)特殊重復(fù)算子[*0],他的作用是什么呢?是向前吃掉一拍的操作,舉幾個(gè)例子感受下:

  • req_a ##N req_b[*0] 等價(jià)于req_a ##N-1 req_b;

  • req_a ##1 req_b[*0] 等價(jià)于req_a;

  • req_a[*0] ##N req_b 等價(jià)于 ##N-1 req_b;

  • req_a[*0] ##1 req_b 等價(jià)于 req_b;

通過這個(gè)特殊算子,我們可以改寫如下([*0]吃掉了##1 ~(wr_en & wr_addr==tmp_addr)):

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##3 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*0] |-> rd_data==tmp_data;
endproperty

好的,四種情景我們已經(jīng)寫好了,下面把他們放在一起來觀察下,仿佛規(guī)律套路很深?。∮^察了一個(gè)小時(shí)后我們發(fā)現(xiàn),里面除了數(shù)字不一樣其他的根本就是完全一樣的。

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##0 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*3] |-> rd_data==tmp_data;
endproperty

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##1 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*2] |-> rd_data==tmp_data;
endproperty

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##2 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*1] |-> rd_data==tmp_data;
endproperty

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##3 (wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*0] |-> rd_data==tmp_data;
endproperty

那么就試著把他們合到一起吧,合到一起是什么樣子呢?

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        (rd_en, tmp_addr=rd_addr) ##0
        ((##[0:3] wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*0:3])) |-> rd_data==tmp_data;
endproperty

就是這樣對(duì)不對(duì)?!可是我們觀察下上面這個(gè)斷言是有明顯問題的,我們希望的是當(dāng)前面取##0后面取[*3],前面取##1后面取[*2],前面取##2后面取[*1],前面取##3后面取[*0]對(duì)吧!那么我們要怎么辦呢?是時(shí)候再把最好用的intersect拿出來了,記得intersect的作用吧,必須前后的序列等長才會(huì)匹配成功,我們想下前面取##0后面取[*3]這個(gè)序列長度是多少呢?是4拍長度對(duì)吧(別忘了里面還插著要給##1呢哈);以此類推,是不是每種匹配的情況都是4拍長度!所以我們只要約束((##[0:3] wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*0:3]))這個(gè)事在4拍內(nèi)匹配就行了呀,怎么約束呢?使用intersect ##3 1‘b1,注意真的不是##4,看一下下面的波形就更清楚了,60ns再##3 1‘b1是在什么時(shí)候匹配的,是不是在120ns處!所以這樣一約束,就使得intersect之前的序列在4拍之內(nèi)匹配成功才會(huì)觸發(fā)斷言的|->檢查了。

這個(gè)技巧真的很好用,望掌握(話說回來,這個(gè)看不懂也沒關(guān)系,太難了我覺得)。

1443365e-958e-11ee-8b88-92fbcf53809c.jpg

答案

property assert_chk;
    reg [31:0] tmp_data;
    reg [31:0] tmp_addr;
    @(posedge clk) disable iff(~rst_n)
        ((rd_en, tmp_addr=rd_addr) ##0
        (((##[0:3] wr_en & wr_addr==tmp_addr, tmp_data=wr_data) ##1 ~(wr_en & wr_addr==tmp_addr)[*0:3])) intersect ##3 1'b1) |-> rd_data==tmp_data;
endproperty

驗(yàn)證

錯(cuò)誤的情況:

1461e93c-958e-11ee-8b88-92fbcf53809c.png
"/home/ICer/test.sv", 510: testbench.u_test.assert_test: started at 365000ps failed at 395000ps
Offending '(rd_data == tmp_data)'
$finish called from file "../top/testbench.sv", line 35.

正確的情況:

146c9508-958e-11ee-8b88-92fbcf53809c.png1470607a-958e-11ee-8b88-92fbcf53809c.jpg

好了,飛不飛升我不知道,反正我人要沒了。


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 信號(hào)
    +關(guān)注

    關(guān)注

    11

    文章

    2741

    瀏覽量

    76185
  • Data
    +關(guān)注

    關(guān)注

    0

    文章

    61

    瀏覽量

    38157
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4237

    瀏覽量

    61973

原文標(biāo)題:【芯片驗(yàn)證】sva_assertion: 15道助力飛升的斷言練習(xí)

文章出處:【微信號(hào):Rocker-IC,微信公眾號(hào):路科驗(yàn)證】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    何為斷言斷言的作用有哪些?斷言的種類 斷言層次結(jié)構(gòu)

    斷言主要用來檢查仿真過程中存在的時(shí)序問題,如果存在異常情況,斷言會(huì)報(bào)警。一般在數(shù)字電路設(shè)計(jì)中都要加入斷言,斷言占整個(gè)設(shè)計(jì)的比例應(yīng)不少于30%。
    的頭像 發(fā)表于 08-28 11:16 ?7447次閱讀
    何為<b class='flag-5'>斷言</b>?<b class='flag-5'>斷言</b>的作用有哪些?<b class='flag-5'>斷言</b>的種類 <b class='flag-5'>斷言</b>層次結(jié)構(gòu)

    sdk-5.2:wiced_tls_init_identity斷言錯(cuò)誤

    在控制臺(tái)調(diào)試生成測試代碼中使用CopyEXEXT命令測試PEAP總是會(huì)碰到斷言。在PEAP情況下,聯(lián)接()調(diào)用WieDig-TLSSI- IITHI恒等式(和;NULL,0,NULL,0);所以它
    發(fā)表于 12-27 15:48

    如何在XC8中使用斷言的?

    大家好,我正在嘗試使用XC8中的斷言,但是當(dāng)我使用“*”時(shí),“斷言h”空格main(空隙){BOOL X=0;斷言(x= 1);而(1){}}我的程序停止,并且在控制臺(tái)中不顯示任何MsAGAGEM
    發(fā)表于 03-26 10:58

    SVA斷言是基于邊沿還是電平呢?

    SVA斷言是一個(gè)強(qiáng)時(shí)序的技術(shù),很多時(shí)候SVA的實(shí)際時(shí)序和驗(yàn)證工程師的期望可能不同,這種不同很難調(diào)試定位。下面是一個(gè)SVA斷言的示例,驗(yàn)證工程
    發(fā)表于 08-25 15:57

    介紹一些SVA基本的概念和常用的語法

    一、序言SVA,即SystemVerilog Assertion,在simulation和Formal都有極為廣泛的應(yīng)用,這里介紹一些基本的概念和常用的語法。二、一個(gè)簡單的例子以一個(gè)arbiter
    發(fā)表于 10-27 16:37

    SVA上廣電D2972-73系列彩電電路圖

    SVA上廣電D2972-73彩色電視機(jī)電路圖,SVA上廣電D2972-73彩電圖紙,SVA上廣電D2972-73原理圖。
    發(fā)表于 05-23 10:55 ?175次下載
    <b class='flag-5'>SVA</b>上廣電D2972-73系列彩電電路圖

    SVA系列(通用)彩電電路圖(1)

    SVA系列彩色電視機(jī)電路圖,SVA系列彩電圖紙,SVA系列原理圖。
    發(fā)表于 05-25 09:25 ?184次下載
    <b class='flag-5'>SVA</b>系列(通用)彩電電路圖(1)

    SVA系列(通用)彩電電路圖(2)

    SVA系列彩色電視機(jī)電路圖,SVA系列彩電圖紙,SVA系列原理圖。 
    發(fā)表于 05-25 09:28 ?90次下載
    <b class='flag-5'>SVA</b>系列(通用)彩電電路圖(2)

    SystemVerilog Assertion Handbo

    SystemVerilog Assertion Handbook1 ROLE OF SYSTEMVERILOG ASSERTIONSIN A VERIFICATION METHODOLOGY
    發(fā)表于 07-22 14:08 ?188次下載

    創(chuàng)建基于斷言的IP

    assertion-based verification. Or perhaps you might think this is a book about assertion patterns that will provide a k
    發(fā)表于 07-23 09:31 ?0次下載
    創(chuàng)建基于<b class='flag-5'>斷言</b>的IP

    SystemVerilog斷言及其應(yīng)用

    在介紹SystemVerilog 斷言的概念、使用斷言的好處、斷言的分類、斷言的組成以及斷言如何被插入到被測設(shè)計(jì)(DUT)的基礎(chǔ)上,本文詳細(xì)
    發(fā)表于 05-24 16:35 ?0次下載
    SystemVerilog<b class='flag-5'>斷言</b>及其應(yīng)用

    SVA Assertion有什么優(yōu)勢?

    如果我們?cè)O(shè)計(jì)正確工作時(shí)需要滿足FRAME_上升沿后的1~2拍會(huì)出現(xiàn)LDP_的下降沿,如下圖所示
    的頭像 發(fā)表于 12-16 09:37 ?459次閱讀

    使用SVA的幾個(gè)好處

    SVA支持多時(shí)鐘域(clock domain crossing (CDC))邏輯,例如異步FIFO。 2. SVA是一種描述語言,可讀性比較強(qiáng)。
    的頭像 發(fā)表于 03-21 14:49 ?668次閱讀

    聊聊形式驗(yàn)證中的SVA

    SVA,即SystemVerilog Assertion,在simulation和Formal都有極為廣泛的應(yīng)用,這里介紹一些基本的概念和常用的語法。
    的頭像 發(fā)表于 06-14 09:31 ?1420次閱讀
    聊聊形式驗(yàn)證中的<b class='flag-5'>SVA</b>

    assertion很痛苦?了解一下SVA Checker Library

    請(qǐng)根據(jù)這段代碼寫一個(gè)assertion檢查 count 每次加5。
    的頭像 發(fā)表于 08-12 09:51 ?1071次閱讀
    寫<b class='flag-5'>assertion</b>很痛苦?了解一下<b class='flag-5'>SVA</b> Checker Library