1.1 結構語句
結構語句主要是initial語句和always語句,initial 語句它在模塊中只執行一次,而always語句則不斷重復執行,以下是一個比較好解釋的圖:
(圖片來源于知乎博主羅成,畫的很好很直觀!)
1.1.1 initial語句
initial 語句它在模塊中只執行一次。
它常用于測試文件的編寫,用來產生仿真測試信號(激勵信號),或者用于對存儲器變量賦初值。
語法格式:
initial begin
??? ...
endPS:當initial與語句內只有一個執行語句時,可以省略begin..end。
1.1.2 always語句
always 語句一直在不斷地重復活動,但是只有和一定的時間控制結合在一起才有作用。
語法格式:
always @ (敏感列表) begin
??? ...
end
PS:敏感列表即觸發always語句執行的條件,多個觸發條件用or連接。同樣,當always語句內只有一個執行語句時,可以省略begin..end。
always語句可用于組合邏輯也可用于時序邏輯,電平觸發往往是組合邏輯,邊沿觸發往往是時序邏輯,因此可進一步細分:
(1)電平觸發——組合邏輯:
????????這個程序表示每當信號abcdefghm的值(即電平變化)發生變化時,always塊中的所有語句都會被執行 。
?????????如果組合邏輯塊語句的輸入變量很多,可簡寫以下形式,@(*)表示對后面語句塊中所有輸入變量的變化都是敏感的(即所有變量有任何一個變化就執行always語句。)
(2)邊沿觸發——時序邏輯:
當檢測到邊沿時,執行always語句,如:
posedge 和 negedge為關鍵字,分別表示上升沿和下降沿,這個程序表示當 sys_clk為上升沿或者 sys_ret_n為下降沿時,執行always語句。
1.1.3 實例理解
?理解:
initial語句中定義了三個信號,sys_clk,sys_rst_n, touch_key,以sys_rst_n, touch_key為例,波形圖對應為第二行和第三行。以下操作只執行了一次。
- 首先sys_rst_n, touch_key均賦值為0(程序從注釋開始算第3行和第5行);
- 代碼第6行,延遲20ns后,sys_rst_n賦值為1,對應于波形圖中紅色線(20ns時刻)時sys_rst_n信號由低電平跳變至高電平。
- 代碼第7行,又延遲10ns后,即30ns處(藍色線),touch_key賦值為1
- 代碼第8~10行,touch_key類似操作。
always語句則不斷重復操作,每延遲10ns,sys_clk就取反一次,故波形圖上(第一行)對應為產生一個周期信號。
1.2 賦值語句
1.2.1? 阻塞賦值 “ = ”
????????阻塞賦值可以認為只有一個步驟的操作:即計算 RHS 并更新LHS(RHS為式子右邊,LHS為式子左邊)。
????????所謂阻塞的概念是指,在同一個always塊中:后面的賦值語句是在前一句賦值語句結束后才開始賦值的。
以上例子理解:
當clk信號為上升沿或者rest_n信號處于下降沿時,執行操作。
- 在波形圖部分,從-6時刻開始,直接clk信號上升沿,且滿足rest_n為低電平,執行if語句,故abc分別賦值為1,2,3。
- 然后 -6 ~ 0時刻,rest_n恒為低電平,每到clk信號上升沿,執行操作中if語句,故-6 ~ 0時刻abc值恒為1,2,3。
- 0時刻時,rest_n跳變為高電平,是上升沿不是下降沿,故不執行操作。
- 0時刻后,rest_n恒為高電平,clk信號第一個上升沿為2時刻,執行操作,此時不滿足if語句(rest_n為高電平),則執行else語句。由于賦值語句是在前一句賦值語句結束后才開始賦值的,故a=0執行完后,b = a = 0執行完, 在執行c = b = 0;
- 2時刻后rest_n恒為高電平,每到clk信號上升沿,執行操作中else語句,故此后abc值都為0。
1.2.2? 非阻塞賦值 “ <=”
????????非阻塞賦值的操作過程可以看作兩個步驟:(1)賦值開始的時候,計算RHS;(2)賦值結束的時候,更新LHS
????????非阻塞賦值可以理解為:第一條非阻塞賦值語句開始時,所有非阻塞語句同時賦值計算好對應的RHS并保存放置一邊,全部計算好后,再將各自保存好的RHS傳遞到對應的LHS中。
??????? 非阻寒賦值只能用于對寄存器類型的變量進行賦值:因此只能用在initial塊和always塊等過程塊中。
以上例子與1.1.1中例子只有阻塞賦值與非阻塞賦值的區別:
同理,當clk信號為上升沿或者rest_n信號處于下降沿時,執行操作。
- 在波形圖部分,從-6時刻開始,直接clk信號上升沿,且滿足rest_n為低電平,執行if語句,賦值語句右邊為1,2,3然后對應賦值到abc上。
- 然后 -6 ~ 0時刻,rest_n恒為低電平,每到clk信號上升沿,執行操作中if語句,故-6 ~ 0時刻abc值恒為1,2,3。
- 0時刻時,rest_n跳變為高電平,是上升沿不是下降沿,故不執行操作。
- 0時刻后,rest_n恒為高電平,clk信號第一個上升沿為2時刻,執行操作,此時不滿足if語句(rest_n為高電平),則執行else語句。賦值語句右邊0,a(值為1),b(值為2)【由于此時ab值為臨近2時刻的值】,則對應將其賦值到abc上得到a=0,b=1,c=2。
- 2時刻后rest_n恒為高電平,4時刻又到了clk信號上升沿,執行操作中else語句,。賦值語句右邊0,a(值為0),b(值為1)【由于此時ab值為臨近4時刻的值】,則對應將其賦值到abc上得到a=0,b=0,c=1;
- 2時刻后rest_n恒為高電平,6時刻又到了clk信號上升沿,執行操作中else語句。賦值語句右邊0,a(值為0),b(值為0)【由于此時ab值為臨近6時刻的值】,則對應將其賦值到abc上得到a=0,b=0,c=0;
- 此后,abc都為0,按照非阻塞也為0了。
1.3 條件語句
條件語句必須在過程塊語句中使用,即是指由initial和always語向引導的塊語句。
1.3.1 if語句
使用方法類似于C語言。
- 允許一定形式的簡寫, if(a) 等同于 if(a==1);if(!a) 等同于 if(a!=1)
- if語句對表達式的值進行判斷,若為0,x,z則按假處理:若為1,按真處理:
- if和else后面的操作語句可以用begin和end包含多個語句。
- 允許if語句的嵌套。
1.3.2 case語句
case (<expression>)
??? case1 :???? ...
??? case2:?? ...
??? case3 :???? ...
??? case4 :???? begin
????????????????????????? <multiple statements>
??????????????????????? end
??? default: <statement>
endcase
語法解釋:
- 其中,case1~case4這些寫的是情況1~4,或者說是看<expression>符合case1~case4的哪一種情況,對應進入執行該情況;
- default表示如果沒有expression沒有匹配的 case 情況,執行 default 語句;
- 看case4知,如果情況中有多個執行語句,用begin..end來寫。????
注意點:
- 分支表達式的值互不相同(即每種情況應不同,不然編譯會出現矛盾)
- 所有表達式的位寬必須相等不能用:bx 來代替:n'bx
除此之外還有另外兩種表達:casez...endcase和casex...endcase。
casez不考慮表達式中的高阻值比較時;casex:不考慮高阻值之和不定值x。
例如:以下例子判定sel的值是否滿足以下哪種情況,情況1是8’b1100_zzzz,其中后四位“zzzz”為高阻值不用考慮,即只需要看前4位是否與sel的值相匹配;情況2是8’b1100_xxzz,后兩位才是高阻值不用考慮,看前6位是否與sel匹配。sel=1100_0011,可知前4位與情況1匹配,前6位與情況2不匹配,故進入情況1。