第一篇:學verilog小結
學習verilog一段時間 小結 學習verilog, verilog, verilog小結
一:基本
Verilog中的變量有線網類型和寄存器類型。線網型變量綜合成wire,而寄存器可能綜合成WIRE,鎖存器和觸發器。
二:verilog語句結構到門級的映射
1、連續性賦值:assign 連續性賦值語句邏輯結構上就是將等式右邊的驅動左邊的結點。因些連續性賦值的目標結點總是綜合成由組合邏輯驅動的結點。Assign語句中的延時綜合時都將忽視。
2、過程性賦值:
過程性賦值只出現在always語句中。
阻塞賦值和非阻塞賦值就該賦值本身是沒有區別的,只是對后面的語句有不同的影響。
建議設計組合邏輯電路時用阻塞賦值,設計時序電路時用非阻塞賦值。
過程性賦值的賦值對象有可能綜合成wire,latch,和flip-flop,取決于具體狀況。如,時鐘控制下的非阻塞賦值綜合成flip-flop。
過程性賦值語句中的任何延時在綜合時都將忽略。
建議同一個變量單一地使用阻塞或者非阻塞賦值。
3、邏輯操作符:
邏輯操作符對應于硬件中已有的邏輯門
4、算術操作符:
Verilog中將reg視為無符號數,而integer視為有符號數。因此,進行有符號操作時使用
integer,使用無符號操作時使用reg。
5、進位:
通常會將進行運算操作的結果比原操作數擴展一位,用來存放進位或者借位。如:
Wire [3:0] A,B;
Wire [4:0] C;Assign C=A+B;C的最高位用來存放進位。
6、關系運算符: 關系運算符:<,>,<=,>= 和算術操作符一樣,可以進行有符號和無符號運算,取決于數據類型是reg,net還是
integer。
7、相等運算符:==,!= 注意:===和!==是不可綜合的。
可以進行有符號或無符號操作,取決于數據類型
8、移位運算符:
左移,右移,右邊操作數可以是常數或者是變量,二者綜合出來的結果不同。
9、部分選擇: 部分選擇索引必須是常量。
10、BIT選擇:
BIT選擇中的索引可以用變量,這樣將綜合成多路(復用)器。
11、敏感表:
Always過程中,所有被讀取的數據,即等號右邊的變量都要應放在敏感表中,不然,綜合時不能正確地映射到所用的門。
12、IF:
如果變量沒有在IF語句的每個分支中進行賦值,將會產生latch。如果IF語句中產生了latch,則IF的條件中最好不要用到算術操作。Case語句類似。Case的條款可以是變量。
如果一個變量在同一個IF條件分支中先贖值然后讀取,則不會產生latch。如果先讀取,后贖值,則會產生latch。
13、循環:
只有for-loop語句是可以綜合的。
14、設計時序電路時,建議變量在always語句中賦值,而在該always語句外使用,使綜合時能準確地匹配。建議不要使用局部變量。
15、不能在多個always塊中對同一個變量贖值
16、函數
函數代表一個組合邏輯,所有內部定義的變量都是臨時的,這些變量綜合后為wire。
17、任務:
任務可能是組合邏輯或者時序邏輯,取決于何種情況下調用任務。
18、Z:
Z會綜合成一個三態門,必須在條件語句中賦值
19、參數化設計:
優點:參數可重載,不需要多次定義模塊
四:模塊優化
1、資源共享:
當進程涉及到共用ALU時,要考慮資源分配問題。可以共享的操作符主要有:關系操作符、加減乘除操作符。通常乘和加不共用ALU,乘除通常在其內部共用。
2、共用表達式: 如:C=A+B;D=G+(A+B);兩者雖然有共用的A+B,但是有些綜合工具不能識別.可以將第二句改為:D=G+C;這樣
只需兩個加法器.
3、轉移代碼:
如循環語句中沒有發生變化的語句移出循環.
4、避免latch:
兩種方法:
1、在每一個IF分支中對變量賦值。
2、在每一個IF語句中都對變量賦初值。
5:模塊:
綜合生成的存儲器如ROM或RAM不是一種好方法。最好用庫自帶的存儲器模塊。
五、驗證: 1、敏感表:
在always語句中,如果敏感表不含時鐘,最好將所有的被讀取的信號都放在敏感表中。
2、異步復位:
建議不要在異步時對變量讀取,即異步復位時,對信號贖以常數值。
第二篇:verilog作業題
1、以結構描述方式實現下列邏輯:
F=AB+ACD(CD的非)
2、以連續賦值語句設計8位總線驅動器。
3、以always語句設計8位總線驅動器。
4、以always語句設計8位雙向總線驅動器。
1、設計一個具有低電平使能端和高電平使能端的2-4譯碼器。
2、設計一個JK觸發器。
3、設計一個24分頻期,要求輸出信號占空比為1:1。
4、一個掛在總線上的16位寄存器。
5、設計一個8位線編碼器,輸入為D7 - D0,D7優先級最高,D0最低。當Di為高電平輸入時,F=1,OUT為其編碼,否則F=0。
1、以結構描述方式實現下列邏輯:
Y=ABC(BC的非)+DE+ CFG(CFG的非)
2、試設計一個具有使能端ncs的2-4譯碼器。
3、試設計一個4位加減運算器,輸入為A、B、CIN、M,輸出為OUT和COUT。當M=0時執行加法運算,M=1時,執行減法運算。
4、試設計一個14分頻器,要求占空比1:1。
5、試設計一個具有三態輸出緩沖的8位數據寄存器。
6、試設計一個具有清0和置數功能的8位二進制加1計數器。
7、設計一個16位移位寄存器。
8、設計一個16位雙向移位寄存器,當d=0時右移, d=1時左移。
1設中斷請求有效電平為高電平,中斷請求輸入線INTR0—INTR15中INTR15優先權最高。試設計一個中斷優先權編碼器。當有中斷請求時,INT=1,同時輸出中斷請求輸入線的編碼V;否則INT=0,V的輸出任意。
2試設計一個具有同步清0和同步置數功能的8位二進制加1計數器。
3試設計一個“11010100”序列檢測器.4設計一個8位雙向移位寄存器。其I/O端口和控制端口包括d(移位方向控制,當d=0時右移, d=1時左移)、數據串行輸入din、數據并行輸入data(8位)、dout數據串行輸出、數據并行輸出q(8位)、同步時鐘clk、并行置數load等。
5設計每周期8個采樣點的鋸齒波信號發生器。
6設計每周期8個采樣點的正弦波信號發生器。
第三篇:verilog學習日志
1.解決xilinx的仿真庫的編輯問題
2.模塊的做法和調用方法,帶參數模塊的應用:兩種方法modelname #(value)madelcase();
二、用defparam 改變參數。
3.Begin ……end之間是串行執行的語句。在實際的電路中各條語句并不是完全串行的。4.Fork……join之間是并行執行的語句,但是不可綜合;
5.表征過程模塊的四種工程模塊:initial模塊,always模塊,task模塊,function模塊;一個程序中可以有多個initial模塊和always模塊,但是initial模塊只執行一次,不可綜合,而always模塊是不斷重復執行的,可以綜合。6.數據類型兩大類:線網類型和寄存器類型
7.線網類型:結構化原件之間的物理連接,默認值高阻z;寄存器表示數據的存儲單元,默認值為x;寄存器類型數據保持最后一次賦值,而線型數據需要持續的驅動; 8.線網數據場用來以關鍵字assign指定組合邏輯信號。模塊中輸入輸出默認為wire類型,可綜合的線網類型有wire,tri,supply0,supply1;線網類型的變量賦值只能通過assign來完成,不能用于always語句。
9.寄存器類型的數據沒有強弱之分,且所有的寄存器類型變量都必須明確給出類型說明(無默認狀態)。10.If語句指定了一個有限編碼邏輯,case結果是并行的,沒有優先級,if……else占用面積小但速度較慢,case語句占用面積大,但速度較快。11.如果if……else語句塊為單句則直接寫就可以,如果不只一句則要用begin……end括起來。12.循環語句for,while,repeat可以綜合,forever不可綜合。13.對于reg型數據不能用assign賦值。
14.拼接數據時最好將數據的進制形式都寫詳細,否則仿真出錯,不知為何?例如:parameter a = 8;b = {{a{1’b0}},c};
15.module mult_8b_for(16.a,b,q 17.);18.parameter bsize = 8;19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.input [bsize1:0] b_t;reg [bsize1)begin
if(b_t[0])
begin
q = q + a_t;//一定要使用阻塞賦值
end else 36.37.38.39.40.begin
q = q;//一定要使用阻塞賦值
end
a_t = a_t <<1;//一定要使用阻塞賦值 b_t = b_t >>1;//一定要使用阻塞賦值
41.42.end end
43.Endmodule
44.Always語句中使用非阻塞賦值“<=”時,只有在always結束后才會把右端的賦值給左邊的寄存器,如果采用非阻塞賦值,則會造成循環語句只執行一次。雖然模塊整體是時序邏輯,但是循環部分卻是組合邏輯。
45.Task和function是綜合的,不過綜合出來都是組合電路。46.在第一行Task語句中不能列出端口名稱。
47.Task中可以調用其他的任務或函數,也可以調用自身;
48.任務定義的結構體內部能出現always或initial過程塊(可能是因為其只能綜合成組合電路的緣故吧)。但是可以在always或initial中調用。調用時要與聲明的端口順序相同。且只能在過程塊中調用。
49.任務的輸出端口必須和寄存器類型的數據變量對應。50.Function不允許有輸出端口的聲明,函數定義在函數內部會隱式的定義一個寄存器變量,該寄存器變量和函數同名并且位寬也一致。函數內部不能調用任務。
51.觸摸板如何禁止:下載一個UltraNav驅動按上,到控制面板鼠標里面就可以禁止觸摸板了。Win7下可以直接去禁止,不用安裝驅動程序。
52.保證敏感信號列表的完備性。不要在組合邏輯中引入環路。
53.同步時序電路的準則:
1、單時鐘策略,單時鐘沿策略。
2、避免使用門控時鐘。
3、不要再子模塊內部使用計數器分頻產生所需時鐘。推薦的方式是有一個專門的子模塊來管理系統時鐘。
54.同步電路在目前數字電路系統中占絕對優勢,和異步電路相比有下列優勢:對溫度、電壓、生產過程等外部參數的適應性強;可以消除毛刺和內部的歪斜的數據,能將設計頻率提高的吉赫茲。但是需要更多的資源,而且其時鐘翻轉頻率高,功耗也比較大。55.關鍵路徑:最大的可能時鐘頻率是由電路中最慢的邏輯路徑決定的。一種消除這種限制的方法是將復雜的運算分開成為數個簡單的運算,這種技術稱為pipelining。56.要輸就輸給追求,要嫁就嫁給幸福。
57.第九章的二級流水線仿真時結果中顯示不對,不知道為何,可能是testbench寫的不好,有時間一定要搞明白。58.提高工作速度的兩種方式:并行方式和流水線方式。核心思想是面積換速度。59.‘timescale 1ns / 1ps 代表時延單位為1ns,時延精度為1ps。
60.亞穩態:多時鐘設計中,必然存在亞穩態,當觸發器的建立時間和保持時間沒有達到要求是,觸發器就會處于邏輯1和邏輯0之間的第3中狀態。及亞穩態。
61.狀態機不僅僅是一種電路,而且是一種設計思想,他可以說是一個廣義時序電路,狀態機是數字設計的“大腦”。
62.狀態機開發流程:首先要抽象出事物的狀態,再次明確狀態和輸入輸出之間的關系,讓后得到系統的狀態轉移圖,并用verilog實現。
63.Moore狀態機輸出僅僅依賴于當前狀態,與輸入無關,下一個狀態與輸入和當前狀態有關,64.Mealy狀態機的輸出與輸入和當前狀態有關,65.狀態機的容錯處理:對剩余狀態進行處理。方法:轉入空閑狀態、轉入特定狀態、轉入預定義的專門處理錯誤的狀態,如報警。66.狀態機設計原則:單獨用一個verilog模塊來描述一個有限狀態機。使用代表狀態名的參數parameter來給狀態賦值,而不是用宏定義。在組合always塊中使用阻塞賦值,在時序always塊中使用非阻塞賦值,67.利用三段式設計狀態機。第一段處理當前狀態的賦值。第二段處理下一個狀態的賦值。第三段處理輸出的賦值。
68.Case后面沒有begin 結尾處加endcase;
69.利用stateCAD做狀態機,注意填寫條件是沒有標點符號,而在寫輸出時有標點;ise軟件在10版本以后就沒有自帶的CAD軟件了,下了一個單獨運行的一樣可以用。70.同步整形電路:同步電路具備最穩定的工作狀態和工作能力因此經常需要將外部輸入的異步信號進行同步處理(與系統時鐘同步)和整形(經輸入信號由不規則的波形提取為具有一個時鐘周期長的脈沖信號)。313頁。71.Assign只能用來給wire和output賦值,不能用來給reg類型賦值;
72.Xst:528-Multi-source in Unit
75.綜合synthesize:查看綜合報告、查看RTL級原理圖、檢查語法。實現:implement,翻譯、映射、布局布線,實現之前要進行約束條件的編輯。76.
第四篇:Verilog學習心得
Verilog學習心得
因為Verilog是一種硬件描述語言,所以在寫Verilog語言時,首先要有所要寫的module在硬件上如何實現的概念,而不是去想編譯器如何去解釋這個module.比如在決定是否使用reg定義時,要問問自己物理上是不是真正存在這個register, 如果是,它的clock是什么? D端是什么?Q端是什么?有沒有清零和置位?同步還是異步?再比如上面討論的三態輸出問題,首先想到的應該是在register的輸出后面加一個三態門,而不是如何才能讓編譯器知道要“賦值”給一個信號為三態。同樣,Verilog中沒有“編譯”的概念,而只有綜合的概念。
寫硬件描述語言的目的是為了綜合,所以說要想寫的好就要對綜合器有很深的了解,這樣寫出來的代碼才有效率。
曾經接觸過motorola蘇州設計中心的一位資深工程師,他忠告了一句:就是用verilog描述電路的時候,一定要清楚它實現的電路,很多人只顧學習verilog語言,而不熟悉它實現的電路,這是設計不出好的電路來的.一般寫verilog code時,對整個硬件的結構應該是很清楚了,最好有詳細的電路圖畫出,時序問題等都應該考慮清楚了。可以看著圖直接寫code。
要知道,最初Verilog是為了實現仿真而發明的.不可綜合的Verilog語句也是很重要的.因為在實際設計電路時,除了要實現一個可綜合的module外,你還要知道它的外圍電路是怎樣的,以及我的這個電路與這些外圍電路能否協調工作.這些外圍電路就可以用不可綜合的語句來實現而不必管它是如何實現的.因為它們可能已經實際存在了,我僅是用它來模擬的.所以,在寫verilog的時候應該要先明確我是用它來仿真的還是綜合的.要是用來綜合的話,就必須要嚴格地使用可綜合的語句,而且不同的寫法可能產生的電路會有很大差別,這時就要懂一些verilog綜合方法的知識.就像前面說的,腦子里要有一個硬件的概念.特別是當綜合報錯時,就要想一想我這種寫法能不能用硬件來實現,verilog畢竟還不是C,很多寫法是不可實現的.要是這個module僅是用來仿真的,就要靈活得多了,這時你大可不必太在意硬件實現.只要滿足它的語法,實現你要的功能就行了.有網友說關于#10 clk=~clk的問題,雖然這種語句是不可綜合的,但是在做simulation和verification是常常用它在testbench中來產生一個clock信號。再比如常常用到的大容量memory, 一般是不會在片上實現的,這個時候也需要一個unsynthesizable module.mengxy所言切中肯罄。
我們設計的module的目的是為了可以綜合出功能正確,符合標準的電路來。我想這是個反復的過程,就像我們在寫design flow中總要注明前仿真,綜合后的仿真,以及后仿真等。仿真是用來驗證我們的設計的非常重要的手段。而verilog里那些看是無聊的語句這個時候就會發揮很大的作用。我想,用過verilog_xl的兄弟應該深有體會。verilog_xl里的操作,可以用verilog里的系統命令來完成。通過最近的應聘我也深有體會,很多公司看中你在寫code時,是否考慮到timing, architecture,DFT等,這也說明verilog中的任何語句都非常重要的。要寫代碼前必須對具體的硬件有一個比較清晰的概念但是想一次完成可綜合代碼就太夸張了,verilog的自頂向下設計方法就是從行為建模開始的,功能驗證了以后再轉向可綜合模型.太在意與可綜合令初期設計變得太累
很同意這種看法,在做邏輯結構設計時,綜合的因素是要考慮的,但是有很多東西不能考慮的過于細致,就是在設計的時候不能過于緊卡時延,面積等因素,因為這樣以來綜合后優化的余量就會很小,反而不利與設計的優化,如果在時延和面積要求不是很緊張的情況下,其實代碼寫的行為級,利用綜合工具進行優化也是一種方法。偶就聽說有一家很有名的公司,非常相信綜合工具的優化能力,從來不作綜合后仿真的,hehe.當然,如果面積和時延的要求很高,最好還是把代碼寫的底層一點,調用庫單元時,也要充分考慮其面積和時延的因素。
Verilog與C++的類比
1.Verilog中的module對應C++中的class。它們都可以實例化。例如可以寫一個FullAdder module,表示全加器這種器件。module FullAdder(a, b, cin, sum, cout);input a, b, cin;output sum, cout;
assign {cout, sum} = a + b + cin;endmodule
然后在執行8-bit補碼加減運算的ALU module中實例化8個FullAdder,表示ALU用到了8個FullAdder。
module ALU(a, b, result, cout, is_add);input[7:0] a, b;input is_add;output[7:0] result;output cout;
wire[7:0] b_not = ~b;wire[7:0] b_in = is_add ? b : b_not;wire[7:0] carry;
assign carry[0] = is_add ? 1'b0 : 1'b1;
// module 實例化
// 8-bit ripple adder FullAdder fa0(a[0], b_in[0], carry[0], result[0], carry[1]);FullAdder fa1(a[1], b_in[1], carry[1], result[1], carry[2]);FullAdder fa2(a[2], b_in[2], carry[2], result[2], carry[3]);FullAdder fa3(a[3], b_in[3], carry[3], result[3], carry[4]);FullAdder fa4(a[4], b_in[4], carry[4], result[4], carry[5]);FullAdder fa5(a[5], b_in[5], carry[5], result[5], carry[6]);FullAdder fa6(a[6], b_in[6], carry[6], result[6], carry[7]);FullAdder fa7(a[7], b_in[7], carry[7], result[7], cout);endmodule
對應在C++中先寫FullAdder class,然后在ALU class中以FullAdder作為data member。
class FullAdder { };
class ALU { FullAdder fa[8];};另外一點,moudle聲明port的方式,像是從早期C語言的函數定義中學來的:
char* strcpy(dst, src)char* dst;char* src;{ //...}
2.Verilog中的模塊調用時,指定端口可以使用名稱綁定。C++在調用函數時,參數只能按順序書寫。例如memset()的原型是:
void *memset(void *s, int c, size_t n);
如果你想將某個buf清零,應該這么寫: char buf[256];memset(buf, 0, sizeof(buf));
但是如果你不小心寫成了: memset(buf, sizeof(buf), 0);
編譯器不會報錯,但運行的實際效果是根本沒有對buf清零。(記得Richard Stevens的書里提到過這一點。)
在Verilog中,如果要寫一個測試ALU的module,那么其中對ALU實例化的指令可以這么寫:
module alu_test;reg[8:0] a_in, b_in;reg op_in;wire[7:0] result_out;wire carry_out;
ALU alu0(.a(a_in[7:0]),.b(b_in[7:0]),.is_add(op_in),.result(result_out),.cout(carry_out));//...endmodule 這樣就比較容易檢查接線錯誤。
另外,在C++中,如果所有參數類型不同,而且之間沒有隱式類型轉換,那么可以利用C++的強類型機制在編譯期檢查出這種調用錯誤。
3.Verilog中把大括弧{}用作bit的并置,因此語句塊要用begin/end標示。Verilog中小括號()和中括號[]的作用與C++中類似,前者用于函數或模塊調用,后者用于下標索引。我想如果Verilog把尖括號<>用作bit并置的話,就能把大括號{}解放出來,用作標示語句塊,這樣寫起來更舒服一些。
4.Verilog本質上是測試驅動開發的。對于每個module都應該有對應的test bench(或稱test fixture)。比較好的情況是,一個工程師寫module,另一個工程師寫對應的testbench,這樣很容易檢查出對電路功能需求理解不一致的地方。因此還可以說Verilog主張結對編程(pair programming)。例如對前面的ALU module的test bench可以寫成: `timescale 1ns / 1ns module alu_test;
reg[8:0] a_in, b_in;reg op_in;
wire[7:0] result_out;wire carry_out;
ALU alu0(.a(a_in[7:0]),.b(b_in[7:0]),.is_add(op_in),.result(result_out),.cout(carry_out));
reg[9:0] get, expected;reg has_error;
initial begin has_error = 1'b0;
op_in = 1'b1;// test addition
for(a_in = 9'b0;a_in!= 256;a_in = a_in + 1)for(b_in = 9'b0;b_in!= 256;b_in = b_in + 1)begin #1;get = {carry_out, result_out};expected = a_in + b_in;if(get!== expected)begin $display(“a_in = %d, b_in = %d, expected %d, get %d”,a_in, b_in, expected, get);has_error = 1'b1;end end
op_in = 1'b0;// test subtraction //...if(has_error === 1'b0)begin $display(“ALL TESTS PASSED!”);end $finish;end endmodule
5.Verilog比起VHDL的不足之處在于,它只能定義concrete class,不能定義abstract class。也就是說interface和implementation不能分離。這在設計大型電路時就顯得表現力不足。不過這關系不大,因為可以在編譯時選擇同一模塊的不同實現版本,間接實現了接口與實現的分離。
在VHDL中,強制將接口與實現分離。對每個模塊,你都得先寫接口(定義輸入輸出信號),即ENTITY;然后至少寫一份實現,即ARCHITECTURE。每個ENTITY可以有不止一份實現,例如可以有行為描述的,也有數據流描述的。然后在配置文件中選擇該ENTITY到底用哪一份實現。舉例來說(選自《VHDL入門·解惑·經典實例·經驗總結》一書),分頻器模塊可以這么寫,先定義其接口FreqDevider,然后定義兩份實現Behavior和Dataflow:
LIBRARY IEEE;USE IEEE.Std_Logic_1164.All;
ENTITY FreqDevider IS PORT(Clock : IN Std_Logic;Clkout : OUT Std_Logic);END;
ARCHITECTURE Behavior OF FreqDevider IS SIGNAL Clk : Std_Logic;BEGIN PROCESS(Clock)BEGIN IF rising_edge(Clock)THEN Clk <= NOT Clk;END IF;END PROCESS;Clkout <= Clk;END;
ARCHITECTURE Dataflow OF FreqDevider IS--signal declarations BEGIN--processes END;在C++中,既可以寫concrete class,也可以寫abstract class。比Verilog和VHDL都方便。
6.Verilog和VHDL都有模板的概念,Verilog稱為參數(parameter),VHDL稱為類屬(generic)。不過好像都只能用整數作為模板參數,不能像C++那樣用類型作為模板參數。
7.目前來看,Verilog是硬件描述語言,不是硬件設計語言。在用Verilog設計電路的時候,我們是把腦子中想好的電路用Verilog“描述”出來:哪里是寄存器、哪里是組合邏輯、數據通路是怎樣、流水線如何運作等等都要在腦子里有清晰的映象。然后用RTL代碼寫出來,經過綜合器綜合出的電路與大腦中的設想相比八九不離十。這就像說C語言是可移植的匯編語言,以前好的C程序員在寫代碼的時候,能夠知道每條語句背后對應的匯編代碼是什么。verilog設計經驗點滴 1,敏感變量的描述完備性
Verilog中,用always塊設計組合邏輯電路時,在賦值表達式右端參與賦值的所有信號都必須在always @(敏感電平列表)中列出,always中if語句的判斷表達式必須在敏感電平列表中列出。如果在賦值表達式右端引用了敏感電平列表中沒有列出的信號,在綜合時將會為沒有列出的信號隱含地產生一個透明鎖存器。這是因為該信號的變化不會立刻引起所賦值的變化,而必須等到敏感電平列表中的某一個信號變化時,它的作用才表現出來,即相當于存在一個透明鎖存器,把該信號的變化暫存起來,待敏感電平列表中的某一個信號變化時再起作用,純組合邏輯電路不可能作到這一點。綜合器會發出警告。Example1: input a,b,c;reg e,d;always @(a or b or c)
begin
e=d&a&b;/*d沒有在敏感電平列表中,d變化時e不會立刻變化,直到a,b,c中某一個變化*/
d=e |c;
end
Example2: input a,b,c;reg e,d;always @(a or b or c or d)
begin
e=d&a&b;/*d在敏感電平列表中,d變化時e立刻變化*/
d=e |c;
end
2, 條件的描述完備性
如果if語句和case語句的條件描述不完備,也會造成不必要的鎖存器。Example1: if(a==1'b1)q=1'b1;//如果a==1'b0,q=? q將保持原值不變,生成鎖存器!
Example2: if(a==1'b1)q=1'b1;else
q=1'b0;//q有明確的值。不會生成鎖存器!Example3: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;//如果a==2'b10或a==2'b11,q=? q將保持原值不變,鎖存器!
endcase Example4: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;
default: q=2'b00;//q有明確的值。不會生成鎖存器!
endcase
Verilog中端口的描述
1,端口的位寬最好定義在I/O說明中,不要放在數據類型定義中; Example1: module test(addr,read,write,datain,dataout)
input[7:0] datain;input[15:0] addr;input
read,write;
output[7:0] dataout;//要這樣定義端口的位寬!
wire addr,read,write,datain;
reg dataout;
Example2: module test(addr,read,write,datain,dataout)input datain,addr,read,write;output dataout;wire[15:0] addr;wire[7:0] datain;wire
read,write;reg[7:0] dataout;// 不要這樣定義端口的位寬!
2,端口的I/O與數據類型的關系:
端口的I/O
端 口 的 數 據 類 型
module內部 module外部
input
wire wire或reg
output
wire或reg
wire
inout
wire
wire
3,assign語句的左端變量必須是wire;直接用“=”給變量賦值時左端變量必須是reg!Example: assign a=b;//a必須被定義為wire!******** begin a=b;//a必須被定義為reg!end
VHDL 中 STD_LOGIC_VECTOR 和 INTEGER 的區別
例如 A 是INTEGER型,范圍從0到255;B是STD_LOGIC_VECTOR,定義為8位。A累加到255時,再加1就一直保持255不變,不會自動反轉到0,除非令其為0;而B累加到255時,再加1就會自動反轉到0。所以在使用時要特別注意!
以觸發器為例說明描述的規范性 1,無置位/清零的時序邏輯
always @(posedge CLK)
begin
Q<=D;
end
2,有異步置位/清零的時序邏輯
異步置位/清零是與時鐘無關的,當異步置位/清零信號到來時,觸發器的輸出立即被置為1或0,不需要等到時鐘沿到來才置位/清零。所以,必須要把置位/清零信號列入always塊的事件控制表達式。
always @(posedge CLK or negedge RESET)
begin
if(!RESET)
Q=0;
else
Q<=D;
end
3,有同步置位/清零的時序邏輯
同步置位/清零是指只有在時鐘的有效跳變時刻置位/清零,才能使觸發器的輸出分別轉換為1或0。所以,不要把置位/清零信號列入always塊的事件控制表達式。但是必須在always塊中首先檢查置位/清零信號的電平。
always @(posedge CLK)
begin
if(!RESET)
Q=0;
else
Q<=D;
end
結構規范性
在整個芯片設計項目中,行為設計和結構設計的編碼是最重要的一個步驟。它對邏輯綜合和布線結果、時序測定、校驗能力、測試能力甚至產品支持都有重要的影響。考慮到仿真器和真實的邏輯電路之間的差異,為了有效的進行仿真測試: 1,避免使用內部生成的時鐘
內部生成的時鐘稱為門生時鐘(gated clock)。如果外部輸入時鐘和門生時鐘同時驅動,則不可避免的兩者的步調不一致,造成邏輯混亂。而且,門生時鐘將會增加測試的難度和時間。
2,絕對避免使用內部生成的異步置位/清零信號
內部生成的置位/清零信號會引起測試問題。使某些輸出信號被置位或清零,無法正常測試。
3,避免使用鎖存器
鎖存器可能引起測試問題。對于測試向量自動生成(ATPG),為了使掃描進行,鎖存器需要置為透明模式(transparent mode),反過來,測試鎖存器需要構造特定的向量,這可非同一般。
4,時序過程要有明確的復位值
使觸發器帶有復位端,在制造測試、ATPG以及模擬初始化時,可以對整個電路進行快速復位。
5,避免模塊內的三態/雙向
內部三態信號在制造測試和邏輯綜合過程中難于處理.補充不知你看了verilog 2001版本嗎?現在的verilog在盡量往C語言的風格上靠攏。
1。敏感變量的描述完備性,我現在用always實現組合邏輯時,都是寫成always@(*),這樣很很好,自動把所有右端賦值信號加入。
2。module編寫時這樣更好: module(input [23:0] rx_data , //CRC_chk interface
output reg
CRC_en ,output reg
CRC_init , input
CRC_err);
第五篇:verilog簡易數字頻率計報告
一、實驗原理
根據原理圖,將計數器模塊、顯示模塊、掃描模塊、譯碼器模塊等分別做出。其原理是在1S內用待測信號給計數器計數,并在一秒結束時給計數器清零,計出來用緩存器緩存,在數碼管中顯示出來。
二、方案論證
一、通過50M的時鐘進行計數獲得精密的1HZ——計數器用Verilog HDL語言實現在1HZ為底電平時計數——門控電路用或門開啟——1HZ為高電平時進行數據鎖存與顯示——利用Verilog HDL語言使前面的0不顯示。
計數器用Verilog HDL語言在寫代碼時可以用復制粘貼的方法可以簡便的實現。通過50M的時鐘進行計數獲得精密的1HZ后只是經過很短的時間內進行計數器的清零及數據的瑣存,并且得到的是1HZ的精密時鐘。把鎖存的數據進行清0的轉換后利用分時掃描,后通過數碼管譯碼顯示。
說明:
Cnt9999:0000~9999計數器; Buffer:鎖存器; Scan:掃描顯示 共8個模塊
三、實驗步驟
一、計數器模塊 計數器模塊的仿真波形
二、鎖存模塊
利用32位的D觸發器進行儲存計數器送給它的數據。在時鐘為上升沿的時候觸發保存數據。鎖存模塊的源代碼:
module buffer_32(clr,clear,in,out);input
clear,clr;input[31:0] in;output[31:0] out;reg[31:0]
out;always@(posedge clear or negedge clr)
if(!clr)out<=0;
//else if(clear)out=in;
else out<=in;
endmodule
三、轉化清零模塊 波形仿真波形
module cnt9999(clr,clk,q,c);
input clr,clk;output c;output [15:0]q;reg c;reg [15:0]q;
always @(posedge clk or negedge clr)begin
if(!clr)begin q[15:0]<=0;c<=1'b0;end
else if(q[15:0]==16'H9999)begin q[15:0]<=0;c<=1'b1;end
else if(q[11:0]==12'H999)begin q[15:0]<=q[15:0]+12'H667;c<=1'b0;end
else if(q[7:0]== 8'H99)begin q[15:0]<=q[15:0]+8'H67;c<=1'b0;end
else if(q[3:0]== 4'H9)begin q[15:0]<=q[15:0]+4'H7;c<=1'b0;end
else begin q[15:0]<=q[15:0]+1'b1;c<=1'b0;end end endmodule
四、掃描顯示模塊
把存儲的數據分別分給8個數碼管,利用循環掃描即可顯示出所要顯示的數據。
掃描顯示模塊的仿真波形
module scan(clk,q);input clk;output [2:0]q;reg
[2:0]q;
always @(posedge clk)
begin
q=q+1;
end
endmodule
四、引腳分配
五、實驗總結
頻率就是信號在1s內發生相同變化的次數,簡易頻率計就是基于這個原理設計的。我們先產生一個低電平為1s,高電平為1/50M秒的周期信號clk,用該信號與待測信號相與作為計數器的輸入時鐘,并把clk的上升沿作為緩存器的開關,把clk的高電平作為計數器的清零信號,這樣就能保證緩沖器中存放的始終是待測信號在一秒內的跳變次數,也即待測信號的頻率。
實驗的原理盡管很清楚,但真正看到實驗現象還是經歷了一番波折,在寫8選1數據選擇器的時候,定義模塊端口時,由于疏忽,把四位位寬漏寫成了1位,結果在數碼管上顯示的始終只有0和1兩種數字。為了改正這個錯誤,我把程序的主要模塊都檢查了一遍,結果不管怎么改實驗現象都沒有出來,這讓我郁悶了很長一段時間,原理明明是對的,為什么就沒有效果呢?最后我把整個程序都打印出來,一行一行地檢查,最后終于找到了癥結所在,就是8選1數據選擇器的位寬弄錯了!經歷了這次錯誤,讓我明白了寫程序還是不能大意,8選1數據選擇器雖然簡單,卻因為位寬這個小小的錯誤讓我浪費了很長的時間,檢查錯誤時也因為其簡單而沒有認真對待。