FPGA除法实现
本文主要通過兩種方法實現乘法器,一種是調用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;
end
always@( * )
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
end
always@(posedge clk)
begin
? ? if((state == IDLE_STATE) & (calculate_en == 1'b1)) begin
? ? ? ? dividend_reg <= dividend;
? ? ? ? divisor_reg <= divisor;
? ? end
end
always@(posedge clk)
begin
? ? if(state == IDLE_STATE)
? ? ? ? shift_cnt <= 4'b0;
? ? else if(state == CALC_STATE)
? ? ? ? shift_cnt <= shift_cnt + 1'b1;
end
always@(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
end
always@(posedge clk)
begin
? ? if(state == END_STATE) begin
? ? ? ? quotient <= quotient_reg;
? ? ? ? remainder <= remainder_reg[4:0];
? ? end
end
? ??
endmodule
?
?
除法器使用位移和相減實現,同樣的,乘法器也可以使用位移與加法實現。更高效率的乘法與除法運算,復雜度較高,還是推薦使用IP核實現。
總結
- 上一篇: 智慧养老之基于RFID技术下的智慧养老解
- 下一篇: requests模拟登录微信公众平台手机