本文主要通过两种方法实现乘法器,一种是调用IP核方式,另一种是使用移位和减法的方式。
一、调用divider generator IP核
赛灵思pg151介绍了除法器IP的使用,简单介绍:
除法器的实现主要有三种方式:LUTMult、Radix-2、High Radix。
1、LUTMult:使用除数的有限精度倒数组成的简单查找表进行查找,然后乘以被除数。
A.使用DSP、块RAM和少量FPGA逻辑实现。
B.仅支持输出余数,不支持输出分数。
C.推荐处理位宽低于12bits的数据
2、Radix-2:小学迭代除法计算方式,计算商和余数
A.使用FPGA逻辑实现。
B.支持输出余数和分数两种。
C.一般使用此种。
3、High Radix:在进行迭代除法之前,进行预缩放处理,可同时生成商多个bits数据
A.使用DPS、块RAM实现。
B.支持输出余数和分数两种。
C.推荐处理位宽高于16bits的数据。
调用该IP核实,AXIS4_stream options—flow control中,Non blocking与blocking区别
Non blocking:非阻塞,此时IP核的S_AXIS_DIVISOR与S_AXIS_DIVIDEND不往外输出axis_ready信号,流水线输出,不判断外部模块是否接收数据
Blocking:阻塞,此时IP核S_AXIS_DIVISOR与S_AXIS_DIVIDEND输出axis_ready信号,控制外部是否可以输入除数与被除数。
二、IP核的仿真验证
IP核参数配置:
module testbench(
);
reg clk=1'b0;
reg [7:0]clk_cnt = 8'd0;
wire [23:0]m_axis_dout_tdata;
reg [15:0] dividend = 16'd0;//被除数
wire [7:0]divisor;
wire [15:0] quotient;//商
wire [7:0] remainder;//余数
always
begin
#5 clk <= ~clk;
end
always@(posedge clk)
begin
clk_cnt <= clk_cnt + 1'b1;
end
always@(posedge clk)
begin
if(clk_cnt == 8'hFF) //间隔256个时钟,被除数加1
dividend <= dividend + 1'b1;
end
assign divisor = 8'd11;
divid_ip divid_ip (
.aclk(clk), // input wire aclk
.s_axis_divisor_tvalid(1'b1), // input wire s_axis_divisor_tvalid
.s_axis_divisor_tdata(divisor), // input wire [7 : 0] s_axis_divisor_tdata
.s_axis_dividend_tvalid(1'b1), // input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata(dividend), // input wire [15 : 0] s_axis_dividend_tdata
.m_axis_dout_tvalid(), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata(m_axis_dout_tdata) // output wire [23 : 0] m_axis_dout_tdata
);
assign quotient = m_axis_dout_tdata[23:8];
assign remainder = m_axis_dout_tdata[7:0];
endmodule
仿真结果如下:
三、FPGA逻辑实现除法器
定义:
被除数:dividend[M-1:0]
除数:divisor[N-1:0]
计算可得:
商:quotient[M-1:0] 位宽为M,与被除数相同
余数:remainder[N-1:0] 位宽为N,与除数相同
先行举例说明:
被除数:dividend[7:0] = 8’d255 = 8’b1111_1111
除数: divisor[3:0] = 4’d11 = 4’b1011
表达如图:
第一次运算: 被除数最高位为1’b1,小于4’b1011,因此商最高位置为0;
第二次运算:被除数高2位为2’b11,小于4’b1011,因此商次高位置为0;
第三次运算:被除数高3位为3’b111,小于4’b1011,因此商的高第3位为0
第四次运算:被除数高4位为4’b1111,大于4’b1011,因此将商的高第4位,为1,将4’b1111减去4’b1011,结果3’b100用于接下来的运算;
第五次运算:将上一次运算的结果3’b100拼接商被除数高第5位数,组合成4’b1001。其小于4’b1011,因此商的高第5位为0;
第六次运算:将上一次运算的结果4’b1001拼接被除数高第6位数,组合成4’b10011。其大于4’b1011,相减后结果为4’b1000,将商第6位置为1;
第七次运算:将上一次运算的结果4’b1000拼接被除数高第7位数,组合成4’b10001。其大于4’b1011,相减后结果为3’b110,将商第7位置为1;
第八次运算:将上一次运算的结果3’b110拼接被除数高第8位数,组合成4’b1101。其大于4’b1011,相减后结果为2’b10,将商第8位置为1;
最终得出,255÷11=23余2。
分析可知,商的位宽与被除数位宽一致,余数的位宽与除数的位宽一致。
四、FPGA逻辑实现除法器,并仿真验证
module divid_gen(
input clk,
input calculate_en,
input [7:0] dividend,
input [3:0] divisor,
output reg [7:0] quotient,
output reg [3:0] remainder
);reg [3:0] shift_cnt;//被除数移位计算计数器
reg [7:0] dividend_reg; //锁存dividend寄存器
reg [3:0] divisor_reg;//锁存divisor寄存器reg [7:0] quotient_reg;//商寄存器,用于缓存每次结算的商结果
reg [7:0] remainder_reg;//余数寄存器,用于缓存每次计算的余数结果reg [1:0] state,next_state;
parameter IDLE_STATE = 2'b00;//空闲态
parameter CALC_STATE = 2'b01;//计算态
parameter END_STATE = 2'b10;//结束态always@(posedge clk)
begin
state <= next_state;
endalways@( * )
begin
case(state)
IDLE_STATE : begin
if(calculate_en)
next_state <= CALC_STATE;
else
next_state <= IDLE_STATE;
end
CALC_STATE : begin
if(shift_cnt >= 8'd8) //移位8次,移位结束,8为被除数的数据宽度
next_state <= END_STATE;
else
next_state <= CALC_STATE;
end
END_STATE : begin
next_state <= IDLE_STATE;
end
default : begin
next_state <= IDLE_STATE;
end
endcase
endalways@(posedge clk)
begin
if((state == IDLE_STATE) & (calculate_en == 1'b1)) begin
dividend_reg <= dividend;
divisor_reg <= divisor;
end
endalways@(posedge clk)
begin
if(state == IDLE_STATE)
shift_cnt <= 4'b0;
else if(state == CALC_STATE)
shift_cnt <= shift_cnt + 1'b1;
endalways@(posedge clk)
begin
case(shift_cnt)
4'd0: begin //第一次运算
if(dividend_reg[7] >= divisor) begin
quotient_reg[7] <= 1'b1;
remainder_reg[7:6] <= {(dividend_reg[7] - divisor),dividend_reg[6]};
end
else begin
quotient_reg[7] <= 1'b0;
remainder_reg[7:6] <= dividend_reg[7:6];
end
end
4'd1: begin //第二次运算
if(remainder_reg[7:6] >= divisor) begin
quotient_reg[6] <= 1'b1;
remainder_reg[7:5] <= {(remainder_reg[7:6] - divisor),dividend_reg[5]};
end
else begin
quotient_reg[6] <= 1'b0;
remainder_reg[7:5] <= {remainder_reg[7:6],dividend_reg[5]};
end
end
4'd2: begin //第三次运算
if(remainder_reg[7:5] >= divisor) begin
quotient_reg[5] <= 1'b1;
remainder_reg[7:4] <= {(remainder_reg[7:5] - divisor),dividend_reg[4]};
end
else begin
quotient_reg[5] <= 1'b0;
remainder_reg[7:4] <= {remainder_reg[7:5],dividend_reg[4]};
end
end
4'd3: begin //第四次运算
if(remainder_reg[7:4] >= divisor) begin
quotient_reg[4] <= 1'b1;
remainder_reg[7:3] <= {(remainder_reg[7:4] - divisor),dividend_reg[3]};
end
else begin
quotient_reg[4] <= 1'b0;
remainder_reg[7:3] <= {remainder_reg[7:4],dividend_reg[3]};
end
end
4'd4: begin //第五次运算
if(remainder_reg[7:3] >= divisor) begin
quotient_reg[3] <= 1'b1;
remainder_reg[7:2] <= {(remainder_reg[7:3] - divisor),dividend_reg[2]};
end
else begin
quotient_reg[3] <= 1'b0;
remainder_reg[7:2] <= {remainder_reg[7:3],dividend_reg[2]};
end
end
4'd5: begin //第六次运算
if(remainder_reg[7:2] >= divisor) begin
quotient_reg[2] <= 1'b1;
remainder_reg[7:1] <= {(remainder_reg[7:2] - divisor),dividend_reg[1]};
end
else begin
quotient_reg[2] <= 1'b0;
remainder_reg[7:1] <= {remainder_reg[7:2],dividend_reg[1]};
end
end
4'd6: begin //第七次运算
if(remainder_reg[7:1] >= divisor) begin
quotient_reg[1] <= 1'b1;
remainder_reg[7:0] <= {(remainder_reg[7:1] - divisor),dividend_reg[0]};
end
else begin
quotient_reg[1] <= 1'b0;
remainder_reg[7:0] <= {remainder_reg[7:1],dividend_reg[0]};
end
end
4'd7: begin //第八次运算
if(remainder_reg[7:0] >= divisor) begin
quotient_reg[0] <= 1'b1;
remainder_reg[7:0] <= (remainder_reg[7:0] - divisor);
end
else begin
quotient_reg[0] <= 1'b0;
remainder_reg[7:0] <= remainder_reg[7:0];
end
end
default :;
endcase
endalways@(posedge clk)
begin
if(state == END_STATE) begin
quotient <= quotient_reg;
remainder <= remainder_reg[4:0];
end
end
endmodule
除法器使用位移和相减实现,同样的,乘法器也可以使用位移与加法实现。更高效率的乘法与除法运算,复杂度较高,还是推荐使用IP核实现。