日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

quartus仿真文件的编写

發(fā)布時(shí)間:2023/12/9 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 quartus仿真文件的编写 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡單組合邏輯-仿真文件的編寫與鞏固

步驟與實(shí)現(xiàn)

  • 簡單組合邏輯-仿真文件的編寫與鞏固
    • 一、二選一選擇器
    • 二、3-8譯碼器
    • 三、半加器
    • 四、層次化設(shè)計(jì)(全加器的實(shí)現(xiàn))

一、二選一選擇器

1.verilog代碼寫完之后,進(jìn)行語法錯(cuò)誤檢查和全編譯,編譯成功之后,需要進(jìn)行仿真文件的編寫,在已有的模板上進(jìn)行修改。(接上一篇如何獲取仿真文件模板)
2.修改主要是進(jìn)行輸入信號(hào)的賦值,仿真文件內(nèi)容組成如下:
(以按鍵點(diǎn)亮自己的led燈仿真文件代碼編譯為例看內(nèi)容組成)

3.二選一選擇器就是,三個(gè)輸入,一個(gè)輸出,當(dāng)選通信號(hào)為低電平,選擇輸入2=輸出,當(dāng)選通信號(hào)為高電平,選擇輸入1=輸出。二選一選擇器verilog代碼如下:

module choose (input wire [0:0] in_1,input wire in_2,input wire sel,output reg out ); always@(*) //*=in_1,in_2,sel信號(hào)if (sel == 1'b1)out = in_1 ;//因?yàn)槭墙M合邏輯,所以使用阻塞賦值,順序進(jìn)行 elseout = in_2; endmodule

新手編輯,output reg 忘記加輸出信號(hào)out報(bào)錯(cuò),該軟件里面的報(bào)錯(cuò)提醒沒有那么詳細(xì),自己敲代碼的時(shí)候一定要注意仔細(xì)!
4.仿真文件代碼(含詳細(xì)注釋)

`timescale 1 ps/ 1 ps //關(guān)鍵詞時(shí)間尺度,時(shí)間單位 1ps module choose_vlg_tst(); //仿真文件名稱 仿真文件:對被仿真的模塊進(jìn)行一個(gè)輸入信號(hào)的模擬//reg eachvec; //類似于時(shí)鐘信號(hào),有clk信號(hào)不用它each,沒有clk信號(hào)時(shí)用它reg [0:0] in_1; reg in_2; reg sel;wire out; //對輸入信號(hào)、輸出信號(hào)進(jìn)行定義//接下來是實(shí)例化,我們需要在仿真文件中調(diào)用被仿真的文件 //我們將仿真模塊中生成的in_1與我們被仿真模塊in_1相連接,實(shí)現(xiàn)了模塊的實(shí)例化 choose i1 (.in_1(in_1),.in_2(in_2),.out(out),.sel(sel) ); initial //上電只執(zhí)行一次,在仿真文件之中,begin end之間的語句順序執(zhí)行,在沒有延時(shí)的情況下,看起來就像是并列運(yùn)行,begin end就相當(dāng)于括號(hào)的作用,在多行賦值時(shí)必須用到 //initial語句主要是為了給輸入信號(hào)進(jìn)行一個(gè)初值的賦值,使用非阻塞賦值,并列運(yùn)行 //在模板中主要需要填寫initial語句,給輸入賦值begin in_1 <= 1'b0;in_2 <= 1'b0;sel <= 1'b0; //初始輸入信號(hào)均賦值為低電平0$display("Running testbench"); end always #10 in_1 <= {$random}%2; always #10 in_2 <= {$random}%2; always #10 sel <= {$random}%2;// 對這三個(gè)輸入信號(hào)進(jìn)行隨機(jī)數(shù)賦值,用always語句 #+時(shí)間單位,#號(hào)表示時(shí)間延時(shí),延時(shí)多少個(gè)時(shí)間單位,使用阻塞賦值 ,系統(tǒng)函數(shù):隨機(jī)數(shù)的產(chǎn)生 $random, 求模運(yùn)算符% //將產(chǎn)生的隨機(jī)數(shù)對2進(jìn)行求模, 產(chǎn)生的值只有0和1,即高電平和低電平的變化 //每隔10ps對in_1進(jìn)行一次賦值,賦值是一個(gè)隨機(jī)數(shù),有可能是0,有可能是1 initialbegin $timeformat(-12,0,"ps",6); //設(shè)置時(shí)間格式的系統(tǒng)函數(shù)//為了便于觀察,寫入監(jiān)測的系統(tǒng)函數(shù)$monitor("@time %t:in_1=%b in_2=%b sel=%b out=%b",$time,in_1,in_2,sel,out); //時(shí)間:各個(gè)信號(hào)的電平變化,即對各個(gè)信號(hào)的電平變化進(jìn)行實(shí)時(shí)打印,方便觀察end//@eachvec; endmodule

過程中有幾個(gè)問題:
①對于代碼中eachvec問題的解決,這里我是都屏蔽了,不屏蔽會(huì)報(bào)錯(cuò),我也不知道怎么解決,屏蔽后能正確得到波形。
問題解釋參見
鏈接: 【原創(chuàng)】菜鳥學(xué)習(xí)Modelsim 之 遇到的問題及解決方法.

看5和6的解答
②系統(tǒng)函數(shù)$timeformat
③系統(tǒng)函數(shù)display 用于信息的顯示與輸出
④為什么報(bào)錯(cuò)?因?yàn)橛⑽淖址椭形淖址牟顒e,這種低級(jí)錯(cuò)誤!

5.RTLSimulation 仿真波形(看sel選通信號(hào)的跳變)

二、3-8譯碼器

1.在寫verilog代碼之前:
①先明確譯碼器含義
編碼的逆過程,把代碼狀態(tài)的特定含義翻譯出來的過程叫譯碼譯碼器是可以將輸入二進(jìn)制代碼的狀態(tài)翻譯成輸出信號(hào),以表示其原來含義的電路。
譯碼器是一種多輸入多輸出組合邏輯電路器件, 其可以分為變量譯碼和顯示譯碼兩類。這里演示3-8譯碼器。
②明確功能
3-8譯碼器,3個(gè)輸入,8位輸出,其輸入輸出真值表如下:

2.編寫verilog代碼,與選擇器類似
這里有兩種編寫方式,if-else分支語句和case分支語句
注意點(diǎn):①8路輸出,位寬8比特

②編碼過程中避免產(chǎn)生latch,要完整描述編碼過程。
if-else多一條else語句,可以任意賦值;
case中default語句,同樣可以任意賦值。
參考鏈接: FPGA設(shè)計(jì)中l(wèi)atch的產(chǎn)生原因、危害與避免措施.

具體編碼實(shí)現(xiàn)如下:

//組合邏輯實(shí)現(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信號(hào)if ({in_1,in_2,in_3} == 3'b000)out = 8'b0000_0001 ;//因?yàn)槭墙M合邏輯,所以使用阻塞賦值,順序進(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é)都不滿足的時(shí)候,輸出這條語句,當(dāng)然也可以輸出別的,可以進(jìn)行任意賦值,這個(gè)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語句簡潔的多,這主要是因?yàn)樵趇f語句中的分支是有優(yōu)先順序的,在if-else語句中存在優(yōu)先級(jí),先判斷第一個(gè)優(yōu)先條件,看條件是否滿足,逐步執(zhí)行;而case語句在任何時(shí)候都不存在優(yōu)先級(jí)的問題,只要這個(gè)條件與下列條件其中一個(gè)吻合,則執(zhí)行。

另外,注意編譯中可能會(huì)出現(xiàn)3個(gè)嚴(yán)重警告:

因?yàn)楫?dāng)前不做時(shí)序分析,故不需要進(jìn)行.sdc文件的編寫(目前我對這一文件的編寫還不清楚)

3.仿真文件的編寫(含詳細(xì)注釋)

`timescale 1 ps/ 1 ps //時(shí)間尺度 module decoder_vlg_tst(); //模塊名//reg eachvec;reg [0:0] in_1; reg in_2; reg in_3; //輸入信號(hào)定義wire [7:0] out; //輸出信號(hào)定義decoder i1 (.in_1(in_1),.in_2(in_2),.in_3(in_3),.out(out) ); //模塊實(shí)例化 initial //輸入信號(hào)的初始化,使用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; //因?yàn)檩斎胄盘?hào)是模擬輸入,always語句進(jìn)行一個(gè)隨機(jī)數(shù)的賦值,不是0就是1 //@eachvec; //為了方便模塊仿真和便于觀察,添加幾個(gè)系統(tǒng)函數(shù) initialbegin $timeformat(-12,0,"ps",6); //設(shè)置時(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); //時(shí)間:各個(gè)信號(hào)的電平變化,即對各個(gè)信號(hào)的電平變化進(jìn)行實(shí)時(shí)打印,方便觀察end endmodule//時(shí)模輸入輸出實(shí)例化,initial初始always賦值加系統(tǒng)(時(shí)間格式和監(jiān)測)

同樣屏蔽了eachvec(對這個(gè)信號(hào)弄得還不是很清楚)

將仿真文件的內(nèi)容和編寫總結(jié)成:
時(shí)模輸入輸出實(shí)例化,initial初始always賦值加系統(tǒng)(時(shí)間格式和監(jiān)測)

4.RTL仿真
包含一些使用技巧:

各個(gè)輸入信號(hào)的初始賦值和隨機(jī)數(shù)賦值都是隨機(jī)的,可以看到輸出能夠很好的實(shí)現(xiàn)譯碼功能。

三、半加器

1.在寫verilog代碼之前:
①先明確半加器含義
半加器——全加器——層次化設(shè)計(jì)方法
加法器主要用于兩個(gè)數(shù)或者多個(gè)數(shù)相加,加法器分為半加器和全加器。
半加器是指對兩個(gè)輸入數(shù)據(jù)位相加,輸出一個(gè)結(jié)果位和進(jìn)位,沒有進(jìn)位輸入的加法器電路,實(shí)現(xiàn)兩個(gè)一位二進(jìn)制數(shù)的加法運(yùn)算電路。
全加器除了加數(shù)和被加數(shù)加和外,還要加上上一級(jí)傳進(jìn)來的進(jìn)位信號(hào)。

②明確功能
半加器,2個(gè)輸入,2個(gè)輸出(一個(gè)結(jié)果,一個(gè)進(jìn)位),其輸入輸出真值表如下:

2.編寫verilog代碼
這里有兩種編寫方式,分別用always@(*)和assign函數(shù)寫。

module half_adder ( input wire [0:0] in_1,input wire in_2,output wire sum,output wire count );assign {count,sum} = in_1 + in_2;/*always@(*)begin{count,sum} <= in_1 + in_2;end //用assign 輸入信號(hào)類型就是wire,用always 輸入信號(hào)類型就是reg!!易錯(cuò) */ endmodule

always@(*)和assign函數(shù)的區(qū)別:
參考1: verilog基本語法之a(chǎn)lways和assign.
參考2: Verilog中 reg和wire 用法和區(qū)別以及always和assign的區(qū)別.

編譯后RTL圖可以看到已經(jīng)被綜合成了一個(gè)加法器。

3.仿真文件編寫(與前兩個(gè)類似)

時(shí)模輸入輸出實(shí)例化,initial初始always賦值加系統(tǒng)(時(shí)間格式和監(jiān)測)

代碼如下:

`timescale 1 ps/ 1 ps //時(shí)間 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) ); //實(shí)例化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; endmodule

4.RTLsimulation結(jié)果

四、層次化設(shè)計(jì)(全加器的實(shí)現(xiàn))

1.在寫verilog代碼之前:
①先明確層次化設(shè)計(jì)含義
數(shù)字電路中根據(jù)模塊層次不同有兩種基本的結(jié)構(gòu)設(shè)計(jì)方法:自底向上和自頂向下的設(shè)計(jì)方法。

自底向上:基本單元——高級(jí)單元——系統(tǒng)
自頂向下:系統(tǒng)——高級(jí)單元——基本單元——子模塊——EDA元件庫中的元件

層次化設(shè)計(jì)思想對這兩種設(shè)計(jì)方法是混合使用的,這里主要是利用層次化設(shè)計(jì)思想基于第三部分的半加器去實(shí)現(xiàn)全加器。
②明確功能,全加器
3路輸入,2路輸出,輸入為:兩個(gè)數(shù)+上一級(jí)的進(jìn)位信號(hào)
這里采用層次化設(shè)計(jì)思想去設(shè)計(jì)。(將一個(gè)全加器分成兩個(gè)半加器)
明確:一個(gè)全加器并不是最基本的結(jié)構(gòu),可以由兩個(gè)半加器構(gòu)成。
結(jié)構(gòu)框圖如圖:

2.verilog代碼編寫
注意點(diǎn):
①需要對兩個(gè)半加器進(jìn)行實(shí)例化;因?yàn)閮蓚€(gè)半加器就是本身的子模塊,類似于兩個(gè)半加器芯片構(gòu)成一個(gè)全加器功能;
②實(shí)例化后的half_adder.v文件還要加載到files中,在創(chuàng)建工程project的時(shí)候就添加進(jìn)去,否則會(huì)報(bào)錯(cuò)!

具體代碼實(shí)現(xiàn)如下:

module full_adder ( input wire [0:0] in_1,input wire in_2,input wire cin,output wire sum, //求和信號(hào)是由第二個(gè)半加器直接輸出,故用wire型output wire count );//端口列表編寫完成wire h0_sum ; wire h0_count ; wire h1_count ;//既然是用半加器實(shí)現(xiàn)全加器,就一定要對半加器實(shí)例化,就是接口對接口要有個(gè)協(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) ); //兩次實(shí)例化,實(shí)例化名稱不能相同//類似于使用兩個(gè)半加器芯片實(shí)現(xiàn)一個(gè)全加器//用assign語句對兩個(gè)進(jìn)位信號(hào)進(jìn)行或運(yùn)算,把最終的結(jié)構(gòu)作為進(jìn)位信號(hào)輸出 assign count = (h0_count | h1_count);endmodule

編譯之后,其RTL視圖如下:

3.仿真文件的編寫

時(shí)模輸入輸出實(shí)例化,initial初始always賦值加系統(tǒng)(時(shí)間格式和監(jiān)測)

`timescale 1 ps/ 1 ps //時(shí)間 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) ); //實(shí)例化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)行仿真時(shí)間的限制,否則在生成波形界面全加器會(huì)一直仿真下去,直到按stop停止,設(shè)置仿真時(shí)間為1us。

4.RTL Simulation仿真結(jié)果
①在sim中查看,最上層為頂層仿真模塊,打開為內(nèi)部兩個(gè)實(shí)例化的半加器模塊;

②默認(rèn)只添加仿真模塊的波形,回到sim界面,添加頂層模塊的波形和實(shí)例化半加器的波形;

③在wave界面使用快捷鍵CTRL+A 全選,CTRL+G對波形進(jìn)行分組,用restart對波形進(jìn)行重新生成(該圖還未重新生成,未設(shè)置仿真時(shí)間為1us,仿真一直在進(jìn)行,數(shù)據(jù)有缺失);

④點(diǎn)擊全局視圖,添加參考線對波形進(jìn)行放大,驗(yàn)證波形。(設(shè)置end simulation at 1us 之后)

管腳綁定——程序固化——上板驗(yàn)證

總結(jié)

以上是生活随笔為你收集整理的quartus仿真文件的编写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。