quartus仿真文件的编写
簡單組合邏輯-仿真文件的編寫與鞏固
步驟與實現(xiàn)
- 簡單組合邏輯-仿真文件的編寫與鞏固
- 一、二選一選擇器
- 二、3-8譯碼器
- 三、半加器
- 四、層次化設(shè)計(全加器的實現(xiàn))
一、二選一選擇器
1.verilog代碼寫完之后,進(jìn)行語法錯誤檢查和全編譯,編譯成功之后,需要進(jìn)行仿真文件的編寫,在已有的模板上進(jìn)行修改。(接上一篇如何獲取仿真文件模板)
2.修改主要是進(jìn)行輸入信號的賦值,仿真文件內(nèi)容組成如下:
(以按鍵點亮自己的led燈仿真文件代碼編譯為例看內(nèi)容組成)
3.二選一選擇器就是,三個輸入,一個輸出,當(dāng)選通信號為低電平,選擇輸入2=輸出,當(dāng)選通信號為高電平,選擇輸入1=輸出。二選一選擇器verilog代碼如下:
新手編輯,output reg 忘記加輸出信號out報錯,該軟件里面的報錯提醒沒有那么詳細(xì),自己敲代碼的時候一定要注意仔細(xì)!
4.仿真文件代碼(含詳細(xì)注釋)
過程中有幾個問題:
①對于代碼中eachvec問題的解決,這里我是都屏蔽了,不屏蔽會報錯,我也不知道怎么解決,屏蔽后能正確得到波形。
問題解釋參見
鏈接: 【原創(chuàng)】菜鳥學(xué)習(xí)Modelsim 之 遇到的問題及解決方法.
看5和6的解答
②系統(tǒng)函數(shù)$timeformat
③系統(tǒng)函數(shù)display 用于信息的顯示與輸出
④為什么報錯?因為英文字符和中文字符的差別,這種低級錯誤!
5.RTLSimulation 仿真波形(看sel選通信號的跳變)
二、3-8譯碼器
1.在寫verilog代碼之前:
①先明確譯碼器含義
編碼的逆過程,把代碼狀態(tài)的特定含義翻譯出來的過程叫譯碼,譯碼器是可以將輸入二進(jìn)制代碼的狀態(tài)翻譯成輸出信號,以表示其原來含義的電路。
譯碼器是一種多輸入多輸出組合邏輯電路器件, 其可以分為變量譯碼和顯示譯碼兩類。這里演示3-8譯碼器。
②明確功能
3-8譯碼器,3個輸入,8位輸出,其輸入輸出真值表如下:
2.編寫verilog代碼,與選擇器類似
這里有兩種編寫方式,if-else分支語句和case分支語句
注意點:①8路輸出,位寬8比特
②編碼過程中避免產(chǎn)生latch,要完整描述編碼過程。
if-else多一條else語句,可以任意賦值;
case中default語句,同樣可以任意賦值。
參考鏈接: FPGA設(shè)計中l(wèi)atch的產(chǎn)生原因、危害與避免措施.
具體編碼實現(xiàn)如下:
//組合邏輯實現(xiàn)3-8譯碼器 module decoder (input wire [0:0] in_1,input wire in_2,input wire in_3,output reg [7:0] out ); /*always@(*) //*=in_1,in_2,in_3信號if ({in_1,in_2,in_3} == 3'b000)out = 8'b0000_0001 ;//因為是組合邏輯,所以使用阻塞賦值,順序進(jìn)行else if({in_1,in_2,in_3} == 3'b001) out = 8'b0000_0010 ;else if({in_1,in_2,in_3} == 3'b010) out = 8'b0000_0100 ;else if({in_1,in_2,in_3} == 3'b011) out = 8'b0000_1000 ;else if({in_1,in_2,in_3} == 3'b100) out = 8'b0001_0000 ;else if({in_1,in_2,in_3} == 3'b101) out = 8'b0010_0000 ;else if({in_1,in_2,in_3} == 3'b110) out = 8'b0100_0000 ;else if({in_1,in_2,in_3} == 3'b111) out = 8'b1000_0000 ; elseout = 8'b0000_0001 ; //當(dāng)上述調(diào)節(jié)都不滿足的時候,輸出這條語句,當(dāng)然也可以輸出別的,可以進(jìn)行任意賦值,這個else語句主要是避免產(chǎn)生latch//產(chǎn)生latch的解釋:https://blog.csdn.net/perfect_lun/article/details/51818886*///另一種分支語句的表示 always@(*)case({in_1,in_2,in_3})3'b000:out = 8'b0000_0001;3'b001:out = 8'b0000_0010;3'b010:out = 8'b0000_0100;3'b011:out = 8'b0000_1000;3'b100:out = 8'b0001_0000;3'b101:out = 8'b0010_0000; 3'b110:out = 8'b0100_0000;3'b111:out = 8'b1000_0000;default:out = 8'b0000_0001;endcase endmodule編寫代碼編譯完成之后,查看并比較其RTL圖。
可以發(fā)現(xiàn)case語句是比if-else語句簡潔的多,這主要是因為在if語句中的分支是有優(yōu)先順序的,在if-else語句中存在優(yōu)先級,先判斷第一個優(yōu)先條件,看條件是否滿足,逐步執(zhí)行;而case語句在任何時候都不存在優(yōu)先級的問題,只要這個條件與下列條件其中一個吻合,則執(zhí)行。
另外,注意編譯中可能會出現(xiàn)3個嚴(yán)重警告:
因為當(dāng)前不做時序分析,故不需要進(jìn)行.sdc文件的編寫(目前我對這一文件的編寫還不清楚)
3.仿真文件的編寫(含詳細(xì)注釋)
`timescale 1 ps/ 1 ps //時間尺度 module decoder_vlg_tst(); //模塊名//reg eachvec;reg [0:0] in_1; reg in_2; reg in_3; //輸入信號定義wire [7:0] out; //輸出信號定義decoder i1 (.in_1(in_1),.in_2(in_2),.in_3(in_3),.out(out) ); //模塊實例化 initial //輸入信號的初始化,使用initial語句,全部初始化為低電平 begin in_1 <= 1'b0;in_2 <= 1'b0;in_3 <= 1'b0;$display("Running testbench"); end always #10 in_1 <= {$random}%2; always #10 in_2 <= {$random}%2; always #10 in_3 <= {$random}%2; //因為輸入信號是模擬輸入,always語句進(jìn)行一個隨機(jī)數(shù)的賦值,不是0就是1 //@eachvec; //為了方便模塊仿真和便于觀察,添加幾個系統(tǒng)函數(shù) initialbegin $timeformat(-12,0,"ps",6); //設(shè)置時間格式//為了便于觀察,寫入監(jiān)測的系統(tǒng)函數(shù)$monitor("@time %t:in_1=%b in_2=%b in_3=%b out=%b",$time,in_1,in_2,in_3,out); //時間:各個信號的電平變化,即對各個信號的電平變化進(jìn)行實時打印,方便觀察end endmodule//時模輸入輸出實例化,initial初始always賦值加系統(tǒng)(時間格式和監(jiān)測)同樣屏蔽了eachvec(對這個信號弄得還不是很清楚)
將仿真文件的內(nèi)容和編寫總結(jié)成:
時模輸入輸出實例化,initial初始always賦值加系統(tǒng)(時間格式和監(jiān)測)
4.RTL仿真
包含一些使用技巧:
各個輸入信號的初始賦值和隨機(jī)數(shù)賦值都是隨機(jī)的,可以看到輸出能夠很好的實現(xiàn)譯碼功能。
三、半加器
1.在寫verilog代碼之前:
①先明確半加器含義
半加器——全加器——層次化設(shè)計方法
加法器主要用于兩個數(shù)或者多個數(shù)相加,加法器分為半加器和全加器。
半加器是指對兩個輸入數(shù)據(jù)位相加,輸出一個結(jié)果位和進(jìn)位,沒有進(jìn)位輸入的加法器電路,實現(xiàn)兩個一位二進(jìn)制數(shù)的加法運(yùn)算電路。
全加器除了加數(shù)和被加數(shù)加和外,還要加上上一級傳進(jìn)來的進(jìn)位信號。
②明確功能
半加器,2個輸入,2個輸出(一個結(jié)果,一個進(jìn)位),其輸入輸出真值表如下:
2.編寫verilog代碼
這里有兩種編寫方式,分別用always@(*)和assign函數(shù)寫。
always@(*)和assign函數(shù)的區(qū)別:
參考1: verilog基本語法之a(chǎn)lways和assign.
參考2: Verilog中 reg和wire 用法和區(qū)別以及always和assign的區(qū)別.
編譯后RTL圖可以看到已經(jīng)被綜合成了一個加法器。
3.仿真文件編寫(與前兩個類似)
時模輸入輸出實例化,initial初始always賦值加系統(tǒng)(時間格式和監(jiān)測)
代碼如下:
`timescale 1 ps/ 1 ps //時間 module half_adder_vlg_tst(); //模塊名//reg eachvec;reg [0:0] in_1; reg in_2;wire count; wire sum; //輸入輸出定義half_adder i1 (.count(count),.in_1(in_1),.in_2(in_2),.sum(sum) ); //實例化initial begin in_1 <= 1'b0;in_2 <= 1'b0;$display("Running testbench"); end //initial初始 always #10 in_1 <= {$random}%2; always #10 in_2 <= {$random}%2; //always賦值initial //initial系統(tǒng)函數(shù)格式+監(jiān)測begin $timeformat(-12,0,"ps",6); $monitor("@time %t:in_1=%b in_2=%b sum=%b count=%b",$time,in_1,in_2,sum,count); end //@eachvec; endmodule4.RTLsimulation結(jié)果
四、層次化設(shè)計(全加器的實現(xiàn))
1.在寫verilog代碼之前:
①先明確層次化設(shè)計含義
數(shù)字電路中根據(jù)模塊層次不同有兩種基本的結(jié)構(gòu)設(shè)計方法:自底向上和自頂向下的設(shè)計方法。
自底向上:基本單元——高級單元——系統(tǒng)
自頂向下:系統(tǒng)——高級單元——基本單元——子模塊——EDA元件庫中的元件
層次化設(shè)計思想對這兩種設(shè)計方法是混合使用的,這里主要是利用層次化設(shè)計思想基于第三部分的半加器去實現(xiàn)全加器。
②明確功能,全加器
3路輸入,2路輸出,輸入為:兩個數(shù)+上一級的進(jìn)位信號
這里采用層次化設(shè)計思想去設(shè)計。(將一個全加器分成兩個半加器)
明確:一個全加器并不是最基本的結(jié)構(gòu),可以由兩個半加器構(gòu)成。
結(jié)構(gòu)框圖如圖:
2.verilog代碼編寫
注意點:
①需要對兩個半加器進(jìn)行實例化;因為兩個半加器就是本身的子模塊,類似于兩個半加器芯片構(gòu)成一個全加器功能;
②實例化后的half_adder.v文件還要加載到files中,在創(chuàng)建工程project的時候就添加進(jìn)去,否則會報錯!
具體代碼實現(xiàn)如下:
module full_adder ( input wire [0:0] in_1,input wire in_2,input wire cin,output wire sum, //求和信號是由第二個半加器直接輸出,故用wire型output wire count );//端口列表編寫完成wire h0_sum ; wire h0_count ; wire h1_count ;//既然是用半加器實現(xiàn)全加器,就一定要對半加器實例化,就是接口對接口要有個協(xié)議對準(zhǔn)half_adder i1 (.count(h0_count),.in_1(in_1),.in_2(in_2),.sum(h0_sum) ); half_adder i2 (.count(h1_count),.in_1(h0_sum),.in_2(cin),.sum(sum) ); //兩次實例化,實例化名稱不能相同//類似于使用兩個半加器芯片實現(xiàn)一個全加器//用assign語句對兩個進(jìn)位信號進(jìn)行或運(yùn)算,把最終的結(jié)構(gòu)作為進(jìn)位信號輸出 assign count = (h0_count | h1_count);endmodule編譯之后,其RTL視圖如下:
3.仿真文件的編寫
時模輸入輸出實例化,initial初始always賦值加系統(tǒng)(時間格式和監(jiān)測)
`timescale 1 ps/ 1 ps //時間 module full_adder_vlg_tst(); //模塊名reg eachvec;reg cin; reg [0:0] in_1; reg in_2;wire count; wire sum; //輸入輸出定義full_adder i1 (.cin(cin),.count(count),.in_1(in_1),.in_2(in_2),.sum(sum) ); //實例化initial begin in_1 <= 1'b0;in_2 <= 1'b0;cin <= 1'b0;$display("Running testbench"); end //initial初始 always #10 cin <= {$random}%2; always #10 in_1 <= {$random}%2; always #10 in_2 <= {$random}%2; //always賦值 initial //initial系統(tǒng)函數(shù)格式+監(jiān)測begin $timeformat(-12,0,"ps",6); $monitor("@time %t:in_1=%b in_2=%b cin=%b sum=%b count=%b",$time,in_1,in_2,cin,sum,count); end endmodule需要注意,這里要進(jìn)行仿真時間的限制,否則在生成波形界面全加器會一直仿真下去,直到按stop停止,設(shè)置仿真時間為1us。
4.RTL Simulation仿真結(jié)果
①在sim中查看,最上層為頂層仿真模塊,打開為內(nèi)部兩個實例化的半加器模塊;
②默認(rèn)只添加仿真模塊的波形,回到sim界面,添加頂層模塊的波形和實例化半加器的波形;
③在wave界面使用快捷鍵CTRL+A 全選,CTRL+G對波形進(jìn)行分組,用restart對波形進(jìn)行重新生成(該圖還未重新生成,未設(shè)置仿真時間為1us,仿真一直在進(jìn)行,數(shù)據(jù)有缺失);
④點擊全局視圖,添加參考線對波形進(jìn)行放大,驗證波形。(設(shè)置end simulation at 1us 之后)
管腳綁定——程序固化——上板驗證
總結(jié)
以上是生活随笔為你收集整理的quartus仿真文件的编写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [react] 请描述下你对react的
- 下一篇: ThreadLocal就是这么简单