1. 信號的產生及always塊使用注意事項
1.1 不要在不同的always塊內為同一個變量賦值。即某個信號出現在<=或=左邊時,只能在一個always塊內。(詳細解釋見 Verilog HDL與數字電路設計 P38)
所以注意,在產生一個信號時,所有產生該信號的條件都應放在一個always塊內考慮。
1.2 不要在同一個always塊內同時使用阻塞賦值(=)和非阻塞賦值(<=)。
1.3 使用always塊描述組合邏輯時使用阻塞賦值(=),在使用always塊描述時序邏輯時使用非阻塞賦值(<=)。簡單理解可以是,在電平敏感的always塊內使用阻塞賦值,在邊沿敏感的always塊內使用非阻塞賦值。
1.4 任何在always塊內被賦值的變量都必須是寄存器型(reg)。即<=或=左邊的信號,必須是reg型,<=或=右邊的信號可以是reg型也可以是wire型。
另,端口聲明中被聲明為input或inout型的端口,只能被定義為線網型(wire);被聲明為output型的端口,則可以被定義為線網型(wire)或者寄存器型(reg)。如果不定義,則默認為線網型(wire)。
1.5 always的敏感列表中可以同時包括多個電平敏感事件,也可以同時包括多個邊沿敏感事件,但不能同時有電平和邊沿敏感事件。另外,敏感列表中,同時包括一個信號的上升沿敏感事件和下降沿敏感事件也是不允許的,因為這兩個事件可以合並為一個電平事件。
2. 總clk的使用
always敏感列表里的邊沿觸發事件,就是一個clk信號,所以在制定ucf時,邊沿觸發事件信號都要被定義在clk IO端口上,有時隨意分配的clk IO端口在Implement時也會出錯。需要到ucf中用
NET "polin" CLOCK_DEDICATED_ROUTE = FALSE; //polin為邊沿觸發事件信號
語句來規避錯誤。
所以在一個程序中,要盡量使用主clk作為always塊的邊沿觸發信號。如果有些變量要通過某個信號的邊沿觸發來產生,那盡量將這個邊沿觸發信號做成一個判斷條件,然后在產生變量時仍用主clk觸發。
例程:要得到LCD大尺寸屏POL信號的2分頻、8分頻、16分頻...,在控制板上撥動開關設置不同的狀態,輸出polout切換到不同的pol輸入的分頻信號。
思路,定義一個counter(cnt_pol)對輸入pol信號進行計數,則cnt_pol的bit0位與pol輸入信號一致,cnt_pol的bit1位為pol信號的2分頻,bit2位為pol的4分頻,bit3位為pol的8分頻,bit4位為pol的16分頻...
counter計數有兩種方法,一種是直接使用pol作為邊沿觸發事件計數:
reg [8:0] cnt_pol;
always @ (posedge polin or negedge rst)
if(!rst) cnt_pol <= 0;
else cnt_pol <= con_pol +1;
(程序中還有一個主clk信號clkin作為其它信號的主時鍾)
上面這種方法比較簡單,但是polin就作為了一個clk信號,只能定義到FPGA的clk IO端口,並且實現時容易報錯。
另一種方法是,采用主時鍾信號為cnt_pol計數的邊沿敏感事件:
reg [8:0] cnt_pol;
reg pold;
wire cnt_event;
always @ (posedge clkin or negedge rst)
if (!rst) pold <= 0;
else pold <= polin;
assign cnt_event = polin & pold;
always @ (posedge clkin or negedge rst)
if (!rst) cnt_pol <= 0;
else if (!cnt_event) ;
else cnt_pol <= cnt_pol +1;
這樣,程序比較多,但整個程序(包括其它部分)只有clkin是clk信號,避免了上述問題。
對這段程序的解釋:cnt_pol計數的機理與第一種方法不同,先通過第一個always塊(寄存器),對polin信號進行延遲,產生pold信號,pold與polin在相位上差一個clkin周期。然后對pold和polin進行與操作並賦值給cnt_event信號,這樣,cnt_event信號的每個高電平,即代表一個polin周期。然后再在第二個always塊中,通過判斷cnt_event的狀態,來對cnt_pol計數。簡單講,就是將polin的上升沿,轉成一個信號的電平狀態,然后通過判斷這個信號電平的狀態來計數。整個過程使用的邊沿觸發信號都是主clk。
原文鏈接:https://blog.csdn.net/phenixyf/article/details/46364193