- 調(diào)用IP計(jì)數(shù)器:
每來一個(gè)cin(進(jìn)位輸入)信號(hào),計(jì)數(shù)器輸出值加一,當(dāng)計(jì)數(shù)值為9且cin為1時(shí),輸出一個(gè)時(shí)鐘長(zhǎng)度的cout(進(jìn)位輸出)信號(hào)。
首先采用調(diào)用quartus種IP的方式,具體步驟:
Tools----IP Catalog:
然后會(huì)調(diào)出IP目錄窗口:
通過搜索counter來添加計(jì)數(shù)器模塊,需要設(shè)置的內(nèi)容有:bit位(幾位輸出寄存器)、計(jì)數(shù)值、?加一or減一、使能方式(clock enable ,count enable)、計(jì)數(shù)方式(時(shí)鐘 or carry in)、清零,置數(shù),預(yù)載等功能。
設(shè)置完成可以直接自己編寫top模塊,然后例化IP,eg:
在頂層模塊,右鍵點(diǎn)擊 set as top-level....
代碼:
module counter_mytop(clk,cin,cout,q);
input wire clk;
input wire cin;
output wire cout; //這里都報(bào)錯(cuò)了,原因均是錯(cuò)誤使用了reg型來例化,
output wire [11:0]q; //應(yīng)該使用wire來例化
wire cout1;
wire cout2;
wire [3:0] q1;
wire [3:0] q2;
wire [3:0] q3;
assign q = {q3,q2,q1};
counter_myip U1(
.cin(cin),
.clock(clk),
.cout(cout1),
.q(q1)
);
counter_myip U2(
.cin(cout1),
.clock(clk),
.cout(cout2),
.q(q2)
);
counter_myip U3(
.cin(cout2),
.clock(clk),
.cout(cout),
.q(q3)
);
endmodule
易錯(cuò)點(diǎn):
在頂層模塊例化的時(shí)候,一定要注意,例化端口的數(shù)據(jù)類型必須是wire型,如下圖:
無論子模塊的端口是reg還是wire型,因?yàn)樽幽K要迅速讀取來自外部信號(hào)的變化情況,所以頂層模塊例化時(shí)必須定義為wire類型?。?/p>
我自己在編譯時(shí)候,就提示錯(cuò)誤了,多個(gè)例化的中間變量or輸入輸出端口都報(bào)錯(cuò)了,因?yàn)槲词褂脀ire類型。
- BCD計(jì)數(shù)器
BCD碼的巨大優(yōu)勢(shì):
(BCD碼,使用4位2進(jìn)制來表示一位10進(jìn)制,可以粗淺理解為將16進(jìn)制直接讀為10進(jìn)制)
示例:
取出1158這個(gè)數(shù)的每一位來分別進(jìn)行操作:
(1)C語言的做法:
1158%10 = 8;//個(gè)位
1158/10? =115;
115%10 = 5;//十位
115/10 =11;
11%10 = 1;//百位
11/10 =1;//千位
顯然,這種方式對(duì)于硬件資源的浪費(fèi)極大,而且硬件對(duì)于除法運(yùn)算會(huì)舍去精度,因此對(duì)于“需要對(duì)數(shù)據(jù)進(jìn)行取各位運(yùn)算、非整體運(yùn)算時(shí)”,采用BCD碼可以大幅度減少運(yùn)算資源占用以及計(jì)算誤差。
如十進(jìn)制的1158,我們直接把它用16'h1158來代替,那么
????????????????16'h1_1_5_8
=16'b0001_0001_1001_1000
在硬件中,只需要讀出高四位數(shù)(0001),即代表千位,低四位(1000),即代表個(gè)位。
這樣完全避免了上面的轉(zhuǎn)化運(yùn)算,可以直接讀取十進(jìn)制的各個(gè)位數(shù)據(jù)?。。?/p>
?BCD計(jì)數(shù)器的最大計(jì)數(shù)值為10,也就是每次記到9,并且來了一個(gè)新的cin信號(hào)時(shí),cout輸出1:
易錯(cuò)點(diǎn):
在剛開始仿真的時(shí)候,發(fā)現(xiàn)出現(xiàn)了一個(gè)這樣的錯(cuò)誤:
999之后再來cin信號(hào),計(jì)數(shù)值錯(cuò)誤,兩個(gè)時(shí)鐘之后,才恢復(fù)正常值,這是因?yàn)?99+1=000,但是個(gè)位向十位傳遞進(jìn)位時(shí),需要一個(gè)周期,十位向百位傳遞進(jìn)位時(shí),也需要一個(gè)周期,所以出問題了,把cout的輸出邏輯改為assign語句(即迅速傳遞進(jìn)位信息),可以解決。
?修改之后的仿真結(jié)果:
自己編寫的10進(jìn)制計(jì)數(shù)器:
仔細(xì)感悟一下q的always塊的條件書寫,體會(huì)條件書寫時(shí)的包含與被包含關(guān)系,理清思路
代碼:
module counter_my(clk,rst,cin,cout,q);
input clk;
input rst;
input cin;
output cout; //進(jìn)位輸出
output reg [3:0]q; //計(jì)數(shù)輸出
//q的輸出邏輯
always@(negedge rst or posedge clk)begin
if(!rst)
q<=4'b0;
else if(cin ==1) //計(jì)數(shù)到10也復(fù)位
begin
if(q==4'b1001)
q<=0;
else
q<=q+1;
end
else
q<=q;
end
//cout的輸出邏輯
assign cout = (q==4'b1001&&cin==1)?1:0;
endmodule
testbench:
`timescale 1ns/1ns
`define clockperiod 20 //時(shí)鐘周期20ns
module counter_myip_testbench;
//激勵(lì)信號(hào)
reg clk;
reg cin;
//檢測(cè)信號(hào)
wire [11:0] q;
wire cout;
//例化待檢測(cè)模塊,這里犯了錯(cuò)誤,例化時(shí)沒加例化名tb1,編譯不報(bào)錯(cuò)但是仿真無法進(jìn)行!!
counter_mytop tb1( .clk(clk),
.cin(cin),
.cout(cout),
.q(q)
);
//激勵(lì)施加過程
initial clk = 1;
always begin
#(`clockperiod/2) clk = ~clk;
end
//
initial begin
repeat(1500)begin
#(`clockperiod*10);
cin = 1;
#(`clockperiod*10);
cin = 0;
end
#1000;
$stop;
end
endmodule
?文章來源地址http://www.zghlxwxcb.cn/news/detail-775210.html
- 小知識(shí)點(diǎn)擴(kuò)展:
?1.仿真時(shí),在modelsim窗口,可以將子模塊的端口也添加進(jìn)波形圖,來觀察子模塊端口的仿真情況:
2.為防止同名稱無法分析,可以在信號(hào)窗口點(diǎn)擊快捷鍵ctrl +G,進(jìn)行快速分組。
3.像下面的延時(shí)語句,雖然是不可綜合語句,但是會(huì)被綜合器忽略,而且反應(yīng)了電路實(shí)際延時(shí)情況,在自己測(cè)試時(shí)使用很方便(工作時(shí)不可以主動(dòng)寫這樣的代碼)。
?文章來源:http://www.zghlxwxcb.cn/news/detail-775210.html
再?gòu)?qiáng)調(diào)一下易錯(cuò)點(diǎn):首先是例化時(shí)要用wire類型,然后是testben中例化的元件名字不能落下,然后要注意計(jì)數(shù)器Q的輸出邏輯的撰寫,條件編寫正確。
voer!
?
?
到了這里,關(guān)于FPGA拾憶_(3):調(diào)用IP 計(jì)數(shù)器&BCD計(jì)數(shù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!