verilog实现除法运算
·
在FPGA中做除法运算需要大量逻辑单元,尤其是高精度或大位宽运算,这会显著增加资源消耗,本文介绍一种使用只verilog不调用任何ip实现除法运算,通过状态机模拟竖式运算过程,其中状态1商最高位,状态2依次从被除数补位做差直到被除数所有位补完计算得到商和余数,如果需要计算小数位可扩展一个状态3继续补0做差即可。
需要注意的是例化此代码时被除数和除数的位宽并不需要严格确定,width1与width2的值可比实际位宽大但需要保证被除数高位0的个数必须大于或等于除数高位0的个数。举个例子被除数为900,实际位宽为10,width1给到12,这时12位的被除数高位有两个0,除数为50,实际位宽为6,width2可填6-8以保证除数高位0的个数小于等于2即可。
代码如下(变量名均用的拼音表示):
module devision
#(
parameter width1 = 60, //被除数位宽
parameter width2 = 15 //除数位宽 被除数高位0的个数必须大于除数高位0的个数!
)
(
input wire clk,
input wire rst_n,
input wire [width1-1:0] beichushu,
input wire [width2-1:0] chushu,
input wire data_in_vld,
output reg [width1-1:0] shang,
output reg [width2-1:0] yushu,
output reg data_out_vld
);
reg [width1-1:0] beichushu_g;
reg [width2-1:0] chushu_g;
reg [ 5:0] wid;
reg [width2 :0] cha;
reg [4:0] state;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
beichushu_g <= 'd0;
chushu_g <= 'd0;
end
else if(data_in_vld)
begin
beichushu_g <= beichushu;
chushu_g <= chushu;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
state <= 5'd0;
shang <= 'd0;
yushu <= 'd0;
data_out_vld <= 1'b0;
cha <= 'd0;
wid <= 'd0;
end
else case(state)
5'd0 :
begin
if(data_in_vld)
state <= 5'd1;
else
state <= 5'd0;
end
5'd1 :
begin
if(beichushu_g[width1-1:width1-width2] >= chushu_g)
begin
cha <= beichushu_g[width1-1:width1-width2] - chushu_g;
state <= 5'd2;
shang <= {shang[width1-2:0],1'b1};
wid <= wid + 1'b1;
end
else if(beichushu_g[width1-1:width1-width2] < chushu_g)
begin
cha <= beichushu_g[width1-1:width1-width2];
state <= 5'd2;
shang <= {shang[width1-2:0],1'b0};
wid <= wid + 1'b1;
end
end
5'd2 :
begin
if(width1-width2 == wid)
begin
if({cha,beichushu_g[0]} >= chushu_g)
begin
shang <= {shang[width1-2:0],1'b1};
yushu <= {cha,beichushu_g[0]} - chushu_g;
state <= 5'd3;
data_out_vld <= 1'b1;
end
else if({cha,beichushu_g[0]} < chushu_g)
begin
shang <= {shang[width1-2:0],1'b0};
yushu <= {cha,beichushu_g[0]};
state <= 5'd3;
data_out_vld <= 1'b1;
end
end
else if({cha,beichushu_g[width1-width2-wid]} >= chushu_g)
begin
cha <= {cha,beichushu_g[width1-width2-wid]} - chushu_g;
wid <= wid + 1'b1;
shang <= {shang[width1-2:0],1'b1};
state <= 5'd2;
end
else if({cha,beichushu_g[width1-width2-wid]} < chushu_g)
begin
cha <= {cha,beichushu_g[width1-width2-wid]};
wid <= wid + 1'b1;
shang <= {shang[width1-2:0],1'b0};
state <= 5'd2;
end
end
5'd3 :
begin
state <= 5'd0;
shang <= 'd0;
yushu <= 'd0;
data_out_vld <= 1'b0;
cha <= 'd0;
wid <= 'd0;
end
default :
begin
state <= 5'd0;
shang <= 'd0;
yushu <= 'd0;
data_out_vld <= 1'b0;
cha <= 'd0;
wid <= 'd0;
end
endcase
endmodule
仿真代码:
`timescale 1ns/1ns
module tb_devision();
reg clk;
reg rst_n;
reg data_in_vld;
wire [29:0] shang;
wire [ 9:0] yushu;
wire data_out_vld;
initial
begin
clk = 1'b0;
rst_n <= 1'b0;
data_in_vld <= 1'b0;
#20
rst_n <= 1'b1;
#100
data_in_vld <= 1'b1;
#120
data_in_vld <= 1'b0;
end
always #10 clk <= ~clk;
devision
#(
.width1 (30 ), //被除数位宽
.width2 (10 ) //除数位宽
)
devision_inst
(
.clk (clk ), //input
.rst_n (rst_n ), //input
.beichushu ('d1548962 ), //input [width1-1:0]
.chushu ('d658 ), //input [width2-1:0]
.data_in_vld (data_in_vld ), //input
.shang (shang ), //output [width1-1:0]
.yushu (yushu ), //output [width2-1:0]
.data_out_vld (data_out_vld ) //output
);
endmodule
仿真结果(1548962 / 658 = 2354,余数为30):

更多推荐



所有评论(0)