在上一節(jié)半加器中,介紹了全加器可看作兩個(gè)半加器和一個(gè)或門組成。
首先半加器是A+B構(gòu)成了{(lán)C,S}。由于全加器多了一個(gè)低位的進(jìn)位,就是將{C,S}再加上Ci-1。此時(shí)再使用一個(gè)半加器將S與Ci-1相加,結(jié)果的低位就是全加器的低位Si。全加器的高位Ci來自于兩個(gè)半加器的高位,如果有一個(gè)高位為1,結(jié)果就為1。
設(shè)計(jì)規(guī)劃
本例中將采用3個(gè)按鍵作為輸入in1,in2和進(jìn)位信號(hào)cin,并采用兩個(gè)LED燈作為信號(hào)輸出count和sum。根據(jù)上一節(jié)中全加器真值表,可以畫出波形圖:
編寫代碼
module full_adder
(
input wire in1 ,
input wire in2 ,
input wire cin ,
output wire sum ,
output wire cout
);
//wire define
wire h0_sum ;
wire h0_cout;
wire h1_cout;
//------------------------half_adder_inst0------------------------
half_adder half_adder_inst0
(
.in1 (in1 ),
.in2 (in2 ),
.sum (h0_sum ),
.cout (h0_cout)
);
//------------------------half_adder_inst1------------------------
half_adder half_adder_inst1
(
.in1 (h0_sum ),
.in2 (cin ),
.sum (sum ),
.cout (h1_cout)
);
assign cout = h0_cout|h1_cout;
endmodule
還記得FPGA從入門到精通(一)中的移位寄存器的實(shí)例化練習(xí)嗎?以module模塊名(輸入,輸出)開頭,以endmodule結(jié)尾。
上一節(jié)中已經(jīng)封裝好了half_adder函數(shù),內(nèi)部的邏輯就不用再次寫了,只需要將外部端口和full_adder的端口對應(yīng)好就可以直接調(diào)用。這就是verilog的方便之處,否則完成這個(gè)程序,需要將半加器的代碼寫兩次。
再上面的全加器結(jié)構(gòu)圖中可以看到端口的對應(yīng),其中除了全加器的5個(gè)端口外,還需要引入三根連線。需要定義wire變量h0_count,h1_count和h0_sum。
下面完成兩次實(shí)例化,上一節(jié)中的半加器有in1,in2,cout,sum四個(gè)端口,第一個(gè)半加器分別對應(yīng)著全加器的輸入端口in1,in2,h0_count,h0_sum,第二個(gè)半加器分別對應(yīng)著上一個(gè)半加器的結(jié)果的低位h0_sum和低位進(jìn)位cin,h1_count1,全加器的結(jié)果的低位sum。全加器的結(jié)果的高位count是h0_count和h1_count的或。
現(xiàn)在將.v文件綜合一定會(huì)報(bào)錯(cuò),因?yàn)檫€沒有將half_adder模塊添加進(jìn)來。所以調(diào)用時(shí)找不到半加器的函數(shù)。因此需要將half_adder.v復(fù)制到文件夾中并添加到Files中:
看RTL視圖,兩個(gè)half_adder模塊是可以展開的:
編寫testbench
`timescale 1ns/1ns
module tb_full_adder();
reg in1;
reg in2;
reg cin;
wire sum ;
wire cout;
initial begin
in1 <= 1'b0;
in2 <= 1'b0;
cin <= 1'b0;
end
always #10 in1 <= {$random} % 2;
always #10 in2 <= {$random} % 2;
always #10 cin <= {$random} % 2;
//------------------------------------------------------------
initial begin
$timeformat(-9, 0, "ns", 6);
$monitor("@time %t:in1=%b in2=%b cin=%b sum=%b cout=%b",$time,in1,in2,cin,sum,cout);
end
//------------------------------------------------------------
//---------------full_adder_inst------------------
full_adder full_adder_inst(
.in1 (in1),
.in2 (in2),
.cin (cin),
.sum (sum),
.cout (cout)
);
endmodule
這里testbench依然是先聲明變量,其中輸入是reg類型,輸出是wire類型。初始化令變量都為0,延時(shí)10ns給輸入隨機(jī)賦值0或1,然后實(shí)例化將tb_full_adder模塊和full_adder模塊端口進(jìn)行連接,就可以觀察波形。
需要注意的是?。?!在本例中引入了打印模塊,可以直觀看到隨機(jī)輸入對應(yīng)輸出的真值表。
$timeformat(units_number, precision_number, suffix_string, minimum_field_wdith);
timefomat的語法:
第一個(gè)參數(shù)units_number表示打印的時(shí)間值的單位,取0 到-15 之間的整數(shù)值:0 表示秒,-3 表示毫秒,-6 表示微秒,-9 表示納秒, -12 表示皮秒, -15 表示飛秒
第二個(gè)參數(shù)precision_number表示打印時(shí)間值時(shí),小數(shù)點(diǎn)后保留的位數(shù)。
第三個(gè)參數(shù)suffix_string在時(shí)間值后面打印時(shí)間單位。其默認(rèn)值為空字符串,如果用ns作為單位可以打印ns。
第四個(gè)參數(shù)MinFieldWidth 是時(shí)間值與單位字符串的最小長度,不足這個(gè)長度,則在字符串之前補(bǔ)空格。其默認(rèn)值為20。
monitor的語法:
$monitor (“format_string”, parameter1, parameter2, … );
當(dāng)在monitor調(diào)用時(shí)對多個(gè)變量進(jìn)行監(jiān)控,當(dāng)monitor監(jiān)控的變量中任何一個(gè)發(fā)生變化時(shí),將會(huì)打印出當(dāng)前仿真時(shí)刻的值;如果$monitor監(jiān)控的所有變量在某一時(shí)刻均不改變,將不會(huì)打印任何信息。本例中會(huì)打印出時(shí)間和5個(gè)端口值。
對比波形
當(dāng)端口多了之后,看波形相對不直觀了,這里可以通過觀察我們剛才打印的數(shù)據(jù)進(jìn)行判斷。通過View-transcript可以觀察transcript窗口:
表格的方式相對直觀多了,且輸出和預(yù)期一致。
分配管腳
全編譯后分配引腳,這里的按鍵和LED燈管腳我們已經(jīng)非常熟悉了。在location這一欄分配引腳,不要和fitterlocation弄混了。
現(xiàn)在cin,in1,in2對應(yīng)S0,S1,S2,cout對應(yīng)LED0,sum對應(yīng)LED1。那么cin,in1,in2按下去表示為0,點(diǎn)亮的LED表示對應(yīng)為輸出為低電平。都不按下去時(shí),應(yīng)該都熄滅,按下去一個(gè)時(shí),LED0亮,按下兩個(gè)時(shí),LED1亮,按下三個(gè)時(shí),兩個(gè)LED同時(shí)亮。
全編譯后上板驗(yàn)證
一個(gè)都不按下時(shí),都不亮
按下一個(gè)時(shí),LED0亮
按下兩個(gè)時(shí),LED1亮
全部按下時(shí),兩個(gè)都亮
組合邏輯電路的實(shí)例就結(jié)束了,后面是簡單的時(shí)序邏輯電路實(shí)例。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21736瀏覽量
603372 -
信號(hào)
+關(guān)注
關(guān)注
11文章
2791瀏覽量
76763 -
波形圖
+關(guān)注
關(guān)注
1文章
34瀏覽量
14936 -
全加器
+關(guān)注
關(guān)注
10文章
62瀏覽量
28506 -
半加器
+關(guān)注
關(guān)注
1文章
29瀏覽量
8793
發(fā)布評論請先 登錄
相關(guān)推薦
評論