FPGA 高手養(yǎng)成記-手把手解析時(shí)序邏輯乘法器代碼
掃描二維碼
隨時(shí)隨地手機(jī)看文章
下面是一段16位乘法器的代碼,大家可以先瀏覽一下,之后我再做詳細(xì)解釋
1module mux16( 2 clk,rst_n, 3 start,ain,bin,yout,done 4); 5 6 input clk; //芯片的時(shí)鐘信號(hào)。 7 input rst_n; //低電平復(fù)位、清零信號(hào)。定義為0表示芯片復(fù)位;定義為1表示復(fù)位信號(hào)無效。 8 input start; //芯片使能信號(hào)。定義為0表示信號(hào)無效;定義為1表示芯片讀入輸入管腳得乘數(shù)和被乘數(shù),并將乘積復(fù)位清零。 9 input[15:0] ain; //輸入a(被乘數(shù)),其數(shù)據(jù)位寬為16bit. 10 input[15:0] bin; //輸入b(乘數(shù)),其數(shù)據(jù)位寬為16bit. 11 output[31:0] yout; //乘積輸出,其數(shù)據(jù)位寬為32bit. 12 output done; //芯片輸出標(biāo)志信號(hào)。定義為1表示乘法運(yùn)算完成. 13 14 reg[15:0] areg; //乘數(shù)a寄存器 15 reg[15:0] breg; //乘數(shù)b寄存器 16 reg[31:0] yout_r; //乘積寄存器 17 reg done_r; 18 reg[4:0] i; //移位次數(shù)寄存器 19 //------------------------------------------------ 20 //數(shù)據(jù)位控制 21 always @(posedge clk or negedge rst_n) 22 if(!rst_n) i <= 5'd0; 23 else if(start && i < 5'd17) i <= i+1'b1; 24 else if(!start) i <= 5'd0; 25 26 //------------------------------------------------ 27 //乘法運(yùn)算完成標(biāo)志信號(hào)產(chǎn)生 28 always @(posedge clk or negedge rst_n) 29 if(!rst_n) done_r <= 1'b0; 30 else if(i == 5'd16) done_r <= 1'b1; //乘法運(yùn)算完成標(biāo)志 31 else if(i == 5'd17) done_r <= 1'b0; //標(biāo)志位撤銷 32 33 assign done = done_r; 34 35 //------------------------------------------------ 36 //專用寄存器進(jìn)行移位累加運(yùn)算 37 always @(posedge clk or negedge rst_n) begin 38 if(!rst_n) begin 39 areg <= 16'h0000; 40 breg <= 16'h0000; 41 yout_r <= 32'h00000000; 42 end 43 else if(start) begin //啟動(dòng)運(yùn)算 44 if(i == 5'd0) begin //鎖存乘數(shù)、被乘數(shù) 45 areg <= ain; 46 breg <= bin; 47 end 48 else if(i > 5'd0 && i < 5'd16) begin 49 if(areg[i-1]) yout_r = {1'b0,yout[30:15]+breg,yout_r[14:1]}; //累加并移位 50 else yout_r <= yout_r>>1; //移位不累加 51 end 52 else if(i == 5'd16 && areg[15]) yout_r[31:16] <= yout_r[31:16]+breg; //累加不移位 53 end 54 end 55 56 assign yout = yout_r; 57endmodule 58
要理解這段代碼,首先要弄明白幾個(gè)點(diǎn)。
-
我們通常寫的十進(jìn)制的乘法豎式,同樣適用于二進(jìn)制。下面我們就以這個(gè)算式為例:1011 x 0111 =0100_1101。
-
兩個(gè)16位的數(shù)相乘,結(jié)果是32位的,沒有32位要在高位補(bǔ)零。
-
計(jì)算兩個(gè)16位的數(shù)相乘需要移位15次。
例如:
1 1 0 1 1 2 x 0 1 1 1 3------------------------------------ 4 1 0 1 1 5 1 0 1 1 6 1 0 1 1 7 0 0 0 0 8------------------------------------ 9 1 0 0 1 1 0 1
前三次計(jì)算是移位的,最后一次沒有移位
-
兩個(gè)16位的數(shù)相加,結(jié)果是17位的,不夠17位最高位補(bǔ)零。
例如語句yout[30:15]+breg,結(jié)果是17位的。
知道了這些,我們就開始看代碼了
-
1)、接口部分注釋寫的很清楚,這里就不提了
-
2)、數(shù)據(jù)位控制部分
1always @(posedge clk or negedge rst_n) 2if(!rst_n) i <= 5'd0; 3else if(start && i < 5'd17) i <= i+1'b1; 4else if(!start) i <= 5'd0;
當(dāng)start為1時(shí),芯片讀入兩個(gè)數(shù),此時(shí)開始計(jì)數(shù),計(jì)數(shù)16次,乘法運(yùn)算開始
-
3)、乘法運(yùn)算完成標(biāo)志信號(hào)產(chǎn)生
1always @(posedge clk or negedge rst_n) 2if(!rst_n) done_r <= 1'b0; 3else if(i == 5'd16) done_r <= 1'b1; //乘法運(yùn)算完成標(biāo)志 4else if(i == 5'd17) done_r <= 1'b0; //標(biāo)志位撤銷 5 6assign done = done_r;
這部分也很好理解
-
4)、專用寄存器進(jìn)行移位累加運(yùn)算
這里為了簡單,就用15到18位代替15到30位


以上部分是最主要的計(jì)算部分,其他地方相對(duì)來說還比較簡單,例如當(dāng)乘數(shù)某一位為0時(shí),不用累加,直接右移,當(dāng)i計(jì)數(shù)到16時(shí),此時(shí)就不用再移位了,可以直接用位數(shù)表示,直接累加即可。
下面是仿真圖





