FPGA之道(37)Verilog中的編寫注意事項(xiàng)
文章目錄

前言
Verilog中的編寫注意事項(xiàng)
大小寫敏感
Verilog中的關(guān)鍵字
范圍定義的正確使用
不要省略begin與end
注釋中斜杠的方向
編譯指令中的前導(dǎo)符號
混用阻塞和非阻塞賦值的危害
仿真雷區(qū)
阻塞賦值順序
敏感量表缺失
仿真死循環(huán)
少用生僻語句
前言
Verilog中的編寫注意事項(xiàng)
大小寫敏感
Verilog是一種case sensitive的語言,即敏感大小寫。例如以下幾個(gè)變量是不一樣的:
reg abc;
reg Abc;
reg aBc;
reg ABC;
在verilog中,它們分別代表4個(gè)不同的寄存器類型,不能搞混。如過定義了一個(gè)寄存器類型變量a,但是使用的時(shí)候?qū)懗葾,編譯器會報(bào)錯(cuò),表示沒有找到A的定義。
Verilog中的關(guān)鍵字
Verilog中的命名也不能與關(guān)鍵字相同, 所以在書寫代碼的時(shí)候也要避免使用了關(guān)鍵字作為標(biāo)識符。以下列舉了Verilog中的一些關(guān)鍵字供大家參考,可以看出Verilog中的關(guān)鍵字都是小寫的,由于Verilog是大小寫敏感的,所以只要標(biāo)識符不完全和關(guān)鍵字一樣即可。
always and assign attribute begin buf bufif0 bufif1 case casex casez cmos deassign default defparam disable edge else end endattribute endcase endfunction endmodule endprimitive endspecify endtable endtask event for force forever fork function highz0 highz1 if ifnone initial inout input integer join medium module large macromodule nand negedge nmos nor not notif0 notif1 or output parameter pmos posedge primitive pull0 pull1 pulldown pullup rcmos real realtime reg release repeat rnmos rpmos rtran rtranif0 rtranif1 scalared signed small specify specparam strength strong0 strong1 supply0 supply1 table task time tran tranif0 tranif1 tri tri0 tri1 triand trior trireg unsigned vectored wait wand weak0 weak1 while wire wor xnor xor
1
2
3
4
5
6
7
8
9
10
不過也恰恰由于Verilog是大小寫敏感的,所以在使用關(guān)鍵字時(shí)切忌要保持全部小寫,例如,如下的使用都是錯(cuò)誤的:
REG a; // wrong, should be “reg”
Wire b; // wrong, should be “wire”
aSSign b = 1’b1; // wrong, should be “assign”
范圍定義的正確使用
在Verilog中,聲明端口或者變量時(shí),往往都需要配合語法來說明位寬信息,例如:
wire [15:0] x;
不過下述定義也是正確的,
wire [0:15] y;
即范圍可以從大到小,也可以從小到大。但是像上述這樣的定義往往會讓人犯迷糊,從而導(dǎo)致使用的時(shí)候出現(xiàn)很多問題。為了能夠正確使用,減少出問題的機(jī)率,我們列舉出范圍參數(shù)的詳細(xì)語法:
[MSB:LSB]
從范圍參數(shù)的詳細(xì)語法我們可以看出,范圍參數(shù)的左邊界是對應(yīng)MSB的,右邊界是對應(yīng)LSB的。所以,如果一個(gè)二進(jìn)制數(shù)c按照從左至右,從MSB到LSB排列,為
c15、c14、c13……、c2、c1、c0;
那么如果做如下操作:
assign x = c;
assign y = c;
則x[15] = c15, x[0] = c0; y[0] = c[15], y[15] = c0;
記住這一對應(yīng)關(guān)系即可自如應(yīng)對范圍定義不統(tǒng)一的問題,不過建議大家還是使用從大到小的范圍定義法,因?yàn)檫@和二進(jìn)制數(shù)的排列是一致的,方便理解和編程,并且在初始化數(shù)組時(shí),有時(shí)候只有按照這種方法定義的數(shù)組才能初始化成功。
除此以外,在早期版本的Verilog語言中,范圍參數(shù)中不允許出現(xiàn)變量,當(dāng)需要根據(jù)變量來選擇范圍的時(shí)候,只能通過單個(gè)索引的方式來完成,例如:
a = b[i:i-3]; //wrong 需要改成 a[3] = b[i]; a[2] = b[i-1]; a[1] = b[i-2]; a[0] = b[i-3];
1
2
3
4
5
6
不過在Verilog2001版本以后,Verilog支持了在范圍中使用變量,并且還引入了新的語法如下:
[
1
2
例如:
1
wire [7:0] b; wire [3:0] a = b[6 -: 4]; //equal to a= b[6:3]; integer i; reg [3:0] c; c <= b[i -: 4]; //must in always
1
2
3
4
5
不要省略begin與end
在Verilog中,很多語句都可以包含一些子語句,例如always程序庫、if條件、for循環(huán)等等。一般情況下,如果某個(gè)分支中子語句的數(shù)量僅有一條的時(shí)候,可以省略begin-end語法。例如:
always@*
if(sel == 1’b1)
a = b;
else
a = c;
不過,為了保證代碼的一致性和可讀性,更為了減少出錯(cuò)的可能,建議大家不要省略begin-end語法。這樣雖然代碼看起來略微長一些,但是無論是從修改還是從閱讀來說都會給我們帶來極大便利。例如上例改寫如下:
always@*
begin
if(sel == 1’b1)
begin
a = b;
end
else
begin
a = c;
end
end
順便提一下,唯一不能省略begin-end語法的是循環(huán)生成語句。
注釋中斜杠的方向
Verilog的注釋符號有兩種:
“//”和“/* … */”
請注意斜杠的方向?yàn)殒I盤中和“?”共用一個(gè)鍵位的斜杠符號,而不是反斜杠“\”。
編譯指令中的前導(dǎo)符號
使用編譯指令時(shí),都需要在前面加一個(gè)前導(dǎo)符號“”,并且在引用宏定義中參數(shù)的時(shí)候也需要加這個(gè)符號來表明。注意,該符號不是單引號“’”,而是位于鍵盤左上角和“~”符號共用一個(gè)鍵位的“”符號。
混用阻塞和非阻塞賦值的危害
如果在一個(gè)always程序塊中,混用阻塞與非阻塞賦值,輕則會造成組合邏輯和時(shí)序邏輯混雜在一起的結(jié)果,給人帶來很大的混亂;重則直接影響仿真或編譯的正確性。
如果給一個(gè)變量混用混用阻塞與非阻塞賦值,那么結(jié)果更是不可預(yù)測,估計(jì)這個(gè)時(shí)候你自己都不知道你是希望它被綜合工具翻譯成連線還是寄存器,此時(shí)只有期待老天保佑了!
仿真雷區(qū)
阻塞賦值順序
從阻塞賦值的意義我們就可以得知,如果代碼書寫的順序改變,那么程序的功能就可能會有變化。這尤其對仿真器影響最大,因?yàn)榉抡嫫魇峭耆凑誚erilog語法來理解程序的。
例如:
always@(a, b)
begin
t = a & b;
c = ~ t;
end
若寫成這樣仿真就會出現(xiàn)問題,即每次a或b改變時(shí),c得到的是上一次a、b的與非結(jié)果:
always@(a, b)
begin
c = ~ t;
t = a & b;
end
若要保證仿真行為正確,可以在敏感量表中添加本來不是輸入變量的變量t。但是帶來的負(fù)面影響就是always必須執(zhí)行兩次才能得到正確的結(jié)果。
always@(a, b)
begin
t = a & b;
c = ~ t;
end
敏感量表缺失
敏感量表的缺失問題一般指的都是組合邏輯always,因?yàn)闀r(shí)序邏輯的敏感量表比較固定,一般不會出問題。如果敏感量表缺失,那么其實(shí)從語法上來看是會引入鎖存的,但是目前的編譯器一般都會幫助客戶補(bǔ)全敏感量表從而避免鎖存的出現(xiàn),而仿真器沒有該功能,所以如果敏感量表缺失,是會影響到仿真結(jié)果的。例如:
always@(a)
begin
t = a & b;
c = ~ t;
end
此時(shí),若b改變,c不會改變,因?yàn)榉抡嫫髡J(rèn)為該程序塊不敏感b的事件。
仿真死循環(huán)
組合邏輯如果表述的不好,很容易造成仿真死循環(huán),例如,類似如下的代碼都是有問題的:
always@*
a = not a;
或
assign b = m + b;
以上反饋如果出現(xiàn)在時(shí)序邏輯中,不會有任何問題,因?yàn)闀r(shí)序邏輯中的賦值要到下一個(gè)周期才會生效。但是如果用在組合邏輯中,由于賦值馬上生效,一旦生效后的值與之前的值不同,又會激發(fā)下一次賦值,如此往復(fù)而無窮盡,所以仿真器會卡在這一時(shí)刻無法走下去。
當(dāng)然了,并不是說一定不能存在反饋,而是不能存在負(fù)反饋,例如SR鎖存器就可以利用正反饋來實(shí)現(xiàn)穩(wěn)定的電路變化。雖然實(shí)際中有存在負(fù)反饋的數(shù)字組合邏輯電路,但是它得到的結(jié)果對數(shù)字邏輯來說是沒有意義的,因此在編程時(shí)請注意避免。
少用生僻語句
正如我們在本篇開頭所說,語言在不斷發(fā)展,仿真器也在不斷發(fā)展,那么肯定是越常用的語法,越規(guī)范的語句,仿真器支持的越好,那些比較生僻的語句,即是仿真器支持,編譯器還不一定支持,所以,建議大家多多使用常用的語法結(jié)構(gòu)進(jìn)行編程,請放心,這完全不會影響你去實(shí)現(xiàn)一個(gè)非常非常復(fù)雜的設(shè)計(jì),反而這才是最好的做法。
FPGA
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。