if和case
需要看對(duì)應(yīng)的視頻,請(qǐng)點(diǎn)擊視頻編號(hào):001100000066?
1、本視頻通過(guò)示例代碼和綜合后的RTL視圖詳解verilog語(yǔ)言中條件運(yùn)算符中的if語(yǔ)句、case語(yǔ)句、選擇語(yǔ)句的使用場(chǎng)景和方法。
2、這是ALTERA和VIVADO視頻
if和case
5.8.2??if語(yǔ)句
“if”語(yǔ)句的語(yǔ)法如下:
if(condition_1)
procedural_statement_1;
{else if(condition_2)
procedural_statement_2};
{else
procedural_statement_3};
其含義為:
如果對(duì)condition_1?條件滿足,不管其余的條件是否滿足,都執(zhí)行procedural_statement_1,
procedural_statement_2和procedural_statement_3都不執(zhí)行。
如果condition_1不滿足而condition_2滿足,則執(zhí)行procedural_statement_2,
而procedural_statement_1和procedural_statement_3都不執(zhí)行。
如果condition_1不滿足并且condition_2也不滿足時(shí),執(zhí)行procedural_statement_3,
而procedural_statement_1和procedural_statement_2都不執(zhí)行。
通過(guò)下面一個(gè)例子來(lái)具體說(shuō)明:
if(Sum < 60) begin
Grade = C;
Total_C = Total_c + 1;
end
else if(Sum < 75) begin
Grade = B;
Total_B =Total_B + 1;
end
else begin
Grade = A;
Total_A =Total_A + 1;
end
注意條件表達(dá)式必須總是用括號(hào)括起來(lái),如果使用if -if - else?格式,
那么可能會(huì)有二義性,如下面的示例所示:
if(Clk)
if(Reset)
Q = 0;
else
Q = D;
這里存在一個(gè)疑問(wèn):最后一個(gè)else?屬于哪一個(gè)if語(yǔ)句??
是屬于第一個(gè)if?的條件(Clk)還是屬于第二個(gè)if的條件?(Reset)??
這在Verilog HDL?中已通過(guò)將else?與最近的沒(méi)有else?的if語(yǔ)句相關(guān)聯(lián)來(lái)解決。
在這個(gè)例子中,?else?與內(nèi)層if?語(yǔ)句相關(guān)聯(lián)。
下面再舉一個(gè)if?語(yǔ)句的例子:
if(Sum < 100)
Sum = Sum + 10;
if(Nickel_In)
Deposit = 5;
elseif (Dime_In)
Deposit = 10;
else if(Quarter_In)
Deposit = 25;
else
Deposit = ERROR;
筆者建議:
1、條件表達(dá)式需用括號(hào)括起來(lái)。
2、若為if - if?語(yǔ)句,請(qǐng)使用塊語(yǔ)句?begin ---end,如下所示。
if(Clk) begin
if(Reset)
Q = 0;
else
Q = D;
end
以上兩點(diǎn)建議是為了使代碼更加清晰,防止出錯(cuò)。
5.8.3??case語(yǔ)句
case?語(yǔ)句是一個(gè)多路條件分支形式,其語(yǔ)法如下:
case(case_expr)
case_item_expr{case_item_expr} :procedural_statement
. . . . . .
[default:procedural_statement]
endcase
case語(yǔ)句下首先對(duì)條件表達(dá)式case_expr求值,然后依次對(duì)各分支項(xiàng)求值并進(jìn)行比較,
執(zhí)行第一個(gè)與條件表達(dá)式值相匹配的分支中的語(yǔ)句??梢栽?個(gè)分支中定義多個(gè)分支項(xiàng),
且這些值不需要互斥。缺省分支覆蓋所有沒(méi)有被分支表達(dá)式覆蓋的其他分支。
例:
case (HEX)
4'b0001 : LED =7'b1111001; // 1
4'b0010 : LED =7'b0100100; // 2
4'b0011 : LED =7'b0110000; // 3
4'b0100 : LED =7'b0011001; // 4
4'b0101 : LED =7'b0010010; // 5
4'b0110 : LED =7'b0000010; // 6
4'b0111 : LED =7'b1111000; // 7
4'b1000 : LED =7'b0000000; // 8
4'b1001 : LED =7'b0010000; // 9
4'b1010 : LED =7'b0001000; // A
4'b1011 : LED =7'b0000011; // B
4'b1100 : LED =7'b1000110; // C
4'b1101 : LED =7'b0100001; // D
4'b1110 : LED =7'b0000110; // E
4'b1111 : LED =7'b0001110; ,// F
default:LED =7'b1000000; // 0
endcase
書(shū)寫(xiě)建議:?case語(yǔ)句的缺省項(xiàng)必須寫(xiě),防止產(chǎn)生鎖存器。
5.8.4?選擇語(yǔ)句
Verilog語(yǔ)法中有一個(gè)常用的選擇語(yǔ)句,其語(yǔ)法形式為:
vect[a +: b]或vect [a -: b];
vect為變量名字,a為起始位置,加號(hào)或者減號(hào)代表著升序或者降序,
b表示進(jìn)行升序或者降序的寬度。
vect[a +: b]等同于vect[a : a+b-1],vect的區(qū)間從a開(kāi)始向大于a的方向進(jìn)行b次計(jì)數(shù);
vect [a -: b]等同于vect[a : a-b+1],vect的區(qū)間從a開(kāi)始向a小的方向進(jìn)行b次計(jì)數(shù)。
a可以是一個(gè)常數(shù)也可以是一個(gè)可變的數(shù),但b必須是一個(gè)常數(shù)。
例1:vect[7 +: 3];
其中,起始位置為7,+代表著升序,寬度為3。即從7開(kāi)始向比7大的方向數(shù)3個(gè)數(shù)。
其等價(jià)形式為:vect[7 +: 3]==vect[7: 9]。
例2:vect[9 -: 4];
其中,起始位置為9,-代表著降序,寬度為4。即從9開(kāi)始向比9小的方向數(shù)4個(gè)數(shù)。
其等價(jià)形式為:vect[9 -:4]==vect[9 : 6]。
在實(shí)際使用的過(guò)程中該語(yǔ)法最常用的形式是將a作為一個(gè)可變的數(shù)來(lái)使用。
例如需要設(shè)計(jì)具有如下功能的代碼:
當(dāng)cnt==0時(shí),將din[7:0]賦值給data[15:8];當(dāng)cnt==1時(shí)將din[7:0]賦值給data[7:0]。
在設(shè)計(jì)的時(shí)候便可以寫(xiě)成:data[15-8*cnt-: 8] <= din[7:0](此時(shí)需要將15-8*cnt視為一個(gè)整體a,
其會(huì)隨著cnt變化而發(fā)生變化),這樣一來(lái)就完成了對(duì)代碼的精簡(jiǎn)工作。
選擇語(yǔ)句的硬件電路結(jié)構(gòu)如下圖所示,其本質(zhì)上是一個(gè)選擇器。當(dāng)cnt==0時(shí),
選中data[15:8]的鎖存器,將din[7:0]賦值給data[15:8],而data[7:0]的鎖存器保持輸出不變;
當(dāng)cnt==1時(shí),選中data[7:0]的鎖存器,將din[7:0]賦值給data[7:0],而data[15:8]的鎖存器保持輸出不變。

用Modelsim對(duì)以上例子進(jìn)行功能仿真后的仿真圖如下所示。

可以看出仿真結(jié)果滿足實(shí)際的設(shè)計(jì)需求。
筆者經(jīng)驗(yàn):在實(shí)際工程中可以多使用選擇語(yǔ)句vect[a +: b]或vect [a -: b]的形式來(lái)進(jìn)行代碼編寫(xiě),
這將有助于精簡(jiǎn)設(shè)計(jì)代碼。
5.8.5?經(jīng)驗(yàn)總結(jié)
if?語(yǔ)句和case語(yǔ)句是Verilog里兩個(gè)非常重要的語(yǔ)句,?if?和?case語(yǔ)句有一定的相關(guān)性,也有一定的區(qū)別。
相同的地方在于兩者幾乎可以實(shí)現(xiàn)一樣的功能,下面主要介紹一下兩者之間的區(qū)別。
if?語(yǔ)句每個(gè)分支之間是有優(yōu)先級(jí)的,綜合得到的電路是類(lèi)似級(jí)聯(lián)的結(jié)構(gòu)。case語(yǔ)句每個(gè)分支是平等的,
綜合得到的電路則是一個(gè)多路選擇器。因此,多個(gè)if else-if語(yǔ)句綜合得到的邏輯電路延時(shí)有可能會(huì)比case語(yǔ)句稍大。
對(duì)于初學(xué)者而言,在一開(kāi)始學(xué)習(xí)Veriolg的過(guò)程中往往喜歡用if else-if語(yǔ)句,因?yàn)檫@種語(yǔ)法表達(dá)起來(lái)更加直接。
但是在運(yùn)行速度比較關(guān)鍵的項(xiàng)目中,使用case語(yǔ)句的效果會(huì)更好。下面通過(guò)一個(gè)具體的案例來(lái)對(duì)比一下,
使用if語(yǔ)句和case語(yǔ)句來(lái)描述同一功能電路的綜合結(jié)果。
首先是用if語(yǔ)句寫(xiě)的代碼:

其綜合后的RTL視圖如下所示。

從上圖中所示的RTL圖可以看到,此電路中含有兩個(gè)二選一多路選擇器,
并且右邊的優(yōu)先級(jí)要高于左邊(因?yàn)閝的值是直接與右邊的二選一選擇器連接),
當(dāng)en[0]不為1時(shí)才會(huì)繼續(xù)判斷en[1]。也就是說(shuō),在if語(yǔ)句下綜合出的電路含有優(yōu)先級(jí)。
接下來(lái)分析一下使用case語(yǔ)句描述的代碼。

其綜合后的RTL視圖如下所示:

可以看出,使用case語(yǔ)句編寫(xiě)的邏輯代碼綜合出的電路是并行的,沒(méi)有優(yōu)先級(jí),
不影響電路的運(yùn)行速度。
雖然在RTL視圖中,兩種語(yǔ)句綜合出的電路存在著較大的差別,但是由于目前的開(kāi)發(fā)工具已經(jīng)足夠智能,
在布局布線的時(shí)候會(huì)自動(dòng)對(duì)電路進(jìn)行優(yōu)化,其最終映射到FPGA內(nèi)部的電路之間基本毫無(wú)差別。


最后總結(jié)一下if語(yǔ)句和case語(yǔ)句之間的區(qū)別與聯(lián)系:
If語(yǔ)句具有優(yōu)先級(jí),當(dāng)if下的條件不滿足時(shí)才執(zhí)行else后面的部分。而case語(yǔ)句是并行的,
沒(méi)有優(yōu)先級(jí),這在兩者綜合出來(lái)的RTL視圖中可以明顯的觀察出來(lái)。但由于現(xiàn)在的仿真和綜合工具已經(jīng)足夠強(qiáng)大,
最后綜合后的結(jié)果if..else...與case...語(yǔ)句其實(shí)并無(wú)不同,只不過(guò)是兩種不同的實(shí)現(xiàn)方式而已,
因此基本上不用考慮這兩者間的區(qū)別。在不影響功能的前提下設(shè)計(jì)師不需要做局部的優(yōu)化工作,
例如不需要考慮if/case語(yǔ)句的資源耗費(fèi)差異、不需要考慮優(yōu)化電路。只有在影響功能(即時(shí)序約束報(bào)錯(cuò))的前提下,
根據(jù)提示對(duì)電路進(jìn)行優(yōu)化。
相關(guān)視頻:https://www.bilibili.com/video/BV1yf4y1R7gH?p=20