5.1.3 Net and Register
一個reg變量只能在一個always語句中賦值 ?。
向量有效位順序的定義一般是從大數到小數。
盡管定義有效位的順序很自由, 但如果采用毫無規則的定義勢必會給作者和讀代碼的人帶來困惑, 如Data[-4 :0] ,則LSB[0][-1][-2][-3][-4]MSB?,或?Data[0 :4] ,則LSB[4][3][2][1][0]MSB, 這兩種情況的定義都不太好 ,推薦?Data[4 :0]?這種格式的定義。
對net和register類型的輸出要做聲明 (在PORT中)。如果一個信號名沒做聲明 Verilog將假定它為一位寬的wire變量。
線網的多種類型 。寄存器的類型。
5.1.4 Expressions
用括號來表示執行的優先級。盡管操作符本身有優先順序, 但用括號來表示優先級對讀者更清晰, 更有意義。
?If?((alpha < beta)?&&?(gamma >= delta)).... 比下面的表達更合意?。 ?
If?(alpha?=?delta)...
用一個函數(function)來代替表達式的多次重復
如果代碼中發現多次使用一個特殊的表達式 ,那么就用一個函數來代替。這樣在以后的版本升級時更便利 ,這種概念在做行為級的代碼設計時同樣使用 ,經常使用的一組描述可以寫到一個任務(task)中 。
5.1.5 IF 語句
向量比較時 比較的向量要相等。
當比較向量時 ,verilog將對位數小的向量做 0 擴展以使它們的長度相匹配 ,它的自動擴展為隱式的。建議采用顯示擴展 ,這個規律同樣適用于向量同常量的比較。
?Reg?Abc?[7:0]; ?Reg?Bca?[3:0]; ?......
?If?(Abc?=?=?{4’b0,?Bca})begin ?.......
?If?(Abc?=?=?8’b0)?begin
每一個If 都應有一個else 和它相對應。
在做硬件設計時 ,常要求條件為真時執行一種動作而條件為假時執行另一動作,即使認為條件為假不可能發生。沒有else可能會使綜合出的邏輯和RTL級的邏輯不同。如果條件為假時不進行任何操作,則用一條空語句.
?always?@(Cond) ?begin
?if?(Cond) ?DataOut?<=?DataIn;
?End ?//?Else? 以上語句DataOut會綜合成鎖存器.
應注意If ..else if ...else if ...else 的優先級
如果變量在If-else 或case 語句中做非完全賦值, 則應給變量一個缺省值 ,即,
?V1?=?2’b00; ?V2?=?2’b00; ?V3?=?2’b00;
?If?(a?=?=?b)?begin ?V1?=?2’b01;?//V3?is?not?assigned
?V2?=?2’b10;
?End Else?if?(a?=?=?c)?begin ?
V2?=?2’b10;?//V1?is?not?assigned ?
V3?=?2’b11;
?End Else?;;
5.1.6 case 語句
case語句通常綜合成一級多路復用器 (圖的右邊部分), 而if-then-else則綜合成優先編碼的串接的多個多路復用器, 如圖的左邊部分。通常 ,使用case 語句要比if語句快 ,優先編碼器的結構僅在信號的到達有先后時使用。條件賦值語句也能綜合成多路復用器, 而case 語句仿真要比條件賦值語句快。
所有的Case 應該有一個default case 允許空語句 Default : ;
5.1.7 Writing functions
在function的最后給function賦值.
?Function?CompareVectors;?//?(Vector1,?Vector2,?Length) ?
Input?[199:0]?Vector1,?Vector2; ?
Input?[31:0]?Length; ?//local?variables
?Integer?i;
?Reg?Equal;
?Begin
??i?=?0; ?
?Equal?=?1; ?
?While?((i
If?(Vector1[i]?!==?Vector2[i]) ??
??Equal?=?0; ?
??Else?; ??
End
???i?=?i?+?1;
??End ??CompareVectors?=?Equal;
End Endfunction?//compareVectors
函數中避免使用全局變量 否則容易引起HDL行為級仿真和門級仿真的差異 如
function?ByteCompare ?input?[15:0]?Vector1
?input?[15:0]?Vector2 ?input?[7:0]?Length ?begin
?if?(ByteSel) ?//?compare?the?upper?byte
?else ?//?compare?the?lower?byte ?
?end endfunction?//?ByteCompare 中使用了全局變量ByteSel, 可能無意在別處修改了 ,導致錯誤結果。最好直接在端口加以定義 。注意 函數與任務的調用均為靜態調用。
5.1.8 Assignment
Verilog 支持兩種賦值 :過程賦值(procedural) 和連續賦值(continuous)。過程賦值用于過程代碼 initial, ? always, task or function)中給reg 和 integer變量 time ealtimereal賦值, ? 而連續賦值一般給wire 變量賦值。
?Always?@(敏感表?敏感表要完整?如果不完整?將會引起仿真和綜合結果不一致 ?always?@(d?or?Clr) ??if?(Clr) ???q?=?1'b0; ?else?if?(e) ???q?=?d; 以上語句在行為級仿真時e的變化將不會使仿真器進入該進程,導致仿真結果錯誤
Assign/deassign 僅用于仿真加速 僅對寄存器有用 ?。
Force/release 僅用于debug 對寄存器和線網均有用 。
避免使用Disable。
對任何reg賦值用非阻塞賦值代替阻塞賦值 reg 的非阻塞賦值要加單位延遲 ,但異步復位可加可不加 。
=與 =的區別
?Always?@(posedge?Clk?or?negedge?Rst_) ?Begin ??
If?(!Rst_)??//?prioritize?the?“if?conditions”?in?if?statement
???Begin ???
?Rega?<=?0;?//non_blocking?assignment ????
Regb?<=?0; ??
?End ??Else?if?(Soft_rst_all)
? ???Begin ?
???Rega?<=?#u_dly?0;?//add?unit?delay ??
??Regb?<=?#u_dly?0; ?
??End ??Else?if?(Load_init) ??
?Begin ???
?Rega?<=?#u_dly?init_rega; ?
??Regb?<=?#u_dly?init_regb; ??
?End ??Else ???Begin ?
???Rega?<=?#u_dly?Rega?<1; ???
?Regb?<=?#u_dly?St_1; ??
?End End?//?end?Rega,?Regb?assignment.
5.1.9 Combinatorial Vs Sequential Logic
如果一個事件持續幾個時鐘周期 設計時就用時序邏輯代替組合邏輯 。如
Wire?Ct_24_e4;?//it?ccarries?info.?Last?over?several?clock?cycles
?Assign?Ct_24_e4?=?(count8bit[7:0]?>=?8’h24)?
&?(count8bit[7:0]?<=?8’he4); 那么這種設計將綜合出兩個8 比特的加法器 而且會產生毛刺 對于這樣的電路 要采用時序設計 代碼如下
?Reg?Ct_24_e4;
?Always?@(poseddge?Clk?or?negedge?Rst_) ?Begin ?
?If?(!Rst_) ???Ct_24_e4?<=?1’b0;
??Else?if?(count8bit[7:0]?=?=?8’he4) ??
?Ct_24_e4?<=?#u_dly?1’b0; ?
?Else?if?(count8bit[7:0]?=?=?8’h23) ?
??Ct_24_e4?<=?#u_dly?1’b1; ?
?Esle?;? ?//內部總線不要懸空?在default狀態?要把它上拉或下拉.
??Wire?OE_default; ??
Assign?OE_default?=?!(oe1?|?oe2?|?oe3); ?
?Assign?bus[31:0]?=??oe1???Data1[31:0]?: ?
??????oe2???Data2[31:0]?: ????
???oe3???Data3[31:0]?: ??
?????oe_default???32’h0000_0000?:
???????32’hzzzz_zzzz;
5.1.10Macros
為了保持代碼的可讀性 常用 ?“ `define ” ? 做常數聲明。
把“define”放在一個獨立的文件中 參數 parameter 必須在一個模塊中定義 不要傳替參數到模塊 仿真測試向量例外 “define”可以在任何地方定義 要把所有的“define”定義在一個文件中 在編譯原代碼時首先要把這個文件讀入 如果希望宏的作用域僅在一個模塊中 就用參數來代替。
5.1.11Comments
對更新的內容更新要做注釋。
在語法塊的結尾做標記。
?//style?1 ?
If?(~OE_?&&?(state?!=?PENDING))?begin ?.... ?End?//?if?enable?=?=?ture?and?ready ?//style?2?---?identical?lables?on?begin?and?end
?If?(~OE_?&&?(state?!=?PENDING))?begin?//drive?data ?
.... ?End?//drive?data ?//?Comment?end
?Function?Calcparity?//Data,?ParityErr ?.... ?Endfunction?//?Calcparity
每一個模塊都應在模塊開始處做模塊級的注釋 參考前面標準模塊頭 。
在模塊端口列表中出現的端口信號 都應做簡要的功能描述。
5.1.12 FSM
VerilogHDL狀態機的狀態分配 VerilogHDL描述狀態機時必須由parameter分配好狀態,這與VHDL不同 VHDL狀態機狀態可以在綜合時分配產生。
組合邏輯和時序邏輯分開用不同的進程。組合邏輯包括狀態譯碼和輸出 時序邏輯則是狀態寄存器的切換。
必須包括對所有狀態都處理 不能出現無法處理的狀態 使狀態機失控 ?。
Mealy機的狀態和輸入有關,而Moore機的狀態轉換和輸入無關。
Mealy 狀態機的例子如下:
?... ?reg?CurrentState,?NextState,?Out1;
?Parameter?S0=0,S1=1; ?always?@(posedge?Clk?or?negedge?Rst_) ?//?state?vector?flip-flops?(sequential) ?
?if?(!Reset) ??CurrentState?=?S0; ?
?else ??CurrentState?<=?#u_dly?NextState;
?always?@(In1?or?In2?or?CurrentState) ?
?//?output?and?state?vector?decode?(combinational) ?
?case?(CurrentState)
??S0:?begin ?
?NextState?<=?#u_dly?S1; ??
Out1?<=?#u_dly?1'b0; ?end ?
?S1:?if?(In1)?begin
??NextState?<=?#u_dly?S0;
??Out1?<=?#u_dly?In2; ?
?end ??else?begin
??NextState?<=?#u_dly?S1;
??Out1?<=?#u_dly?!In2;
??end ?
?endcase ?endmodule
編輯:黃飛
評論
查看更多