FPGA除法之迭代除法器
FPGA的除法运算有恢复余数法、不恢复余数法(加减交替法)、Goldschmidt方法、泰勒级数展开等,今天来介绍一种较为简单的迭代除法,以及仿真验证。
基本的算法如下:
如图介绍了算法的基本流程,在实现的方面,需要注意以下几点:
1、首先需要先要进行归一化,在这里我们默认被除数是大于除数的,然后我们需要将除数归一化到小于被除数但大于等于1/2的被除数。
2、以移位的次数作为结束的标志,这里我们一共移位6次。
具体实现的代码如下:
1 // ********************************************************************************* 2 // Project Name : 3 // Email : 4 // Create Time : 2022/02/18 19:08 5 // Module Name : Divide 6 // editor : Qing 7 // Version : Rev1.0.0 8 // ********************************************************************************* 9 10 module Divide( 11 input clk , 12 input rst_n , 13 14 input [27:0] divisor , 15 input [27:0] dividend , 16 17 output [27:0] quotient , 18 output [13:0] shift 19 ); 20 21 //========================================================================\ 22 // =========== Define Parameter and Internal signals =========== 23 //========================================================================/ 24 25 reg [13:0] count ; 26 reg [13:0] shift_count ; 27 reg [27:0] divisor_reg ; 28 reg [27:0] quotient_reg; 29 30 reg [27:0] remainder_reg; 31 reg [27:0] remainder_temp; 32 33 reg [27:0] compare ; 34 35 reg shift_flag ; 36 37 //============================================================================= 38 //**************************** Main Code ******************************* 39 //============================================================================= 40 41 always @(posedge clk or posedge rst_n) begin 42 if(rst_n) begin 43 compare <= dividend - divisor; 44 shift_count <= 28'd0; 45 shift_flag <= 1'b0; 46 divisor_reg <= divisor; 47 end 48 else if(compare[27] == 1'b0) begin 49 shift_count <= shift_count + 1'b1; 50 divisor_reg = divisor_reg << 1; 51 compare <= dividend - divisor_reg; 52 end 53 else begin 54 shift_flag <= 1'b1; 55 divisor_reg <= divisor << (shift_count - 1'b1); 56 end 57 end 58 59 assign shift = shift_count - 1; 60 61 always @(posedge clk or posedge rst_n) begin 62 if(rst_n) begin 63 remainder_temp <= 28'd0; 64 count <= 14'd0; 65 remainder_reg <= dividend; 66 quotient_reg <= 28'd0; 67 end 68 else if(shift_flag && (count < 27)) begin 69 remainder_temp = remainder_reg - divisor_reg; 70 if(!remainder_temp[27]) begin 71 quotient_reg <= (quotient_reg << 1) + 1; 72 remainder_reg <= remainder_temp << 1; 73 end 74 else if(remainder_temp[27])begin 75 quotient_reg <= quotient_reg << 1; 76 remainder_reg = remainder_reg << 1; 77 end 78 count <= count + 1'b1; 79 end 80 end 81 82 assign quotient = quotient_reg; 83 84 endmodule
仿真代码:
1 `timescale 1ns/1ps 2 3 module Divide_tb; 4 reg clk ; 5 reg rst_n ; 6 7 reg [27:0] divisor ; 8 reg [27:0] dividend ; 9 10 wire [27:0] quotient ; 11 wire [13:0] shift ; 12 13 Divide Divide_inst( 14 .clk ( clk ), 15 .rst_n ( rst_n ), 16 .divisor ( divisor ), 17 .dividend ( dividend ), 18 .quotient ( quotient ), 19 .shift ( shift ) 20 ); 21 22 initial 23 begin 24 $fsdbDumpfile("wave.fsdb"); 25 $fsdbDumpvars(0,Divide_tb); 26 end 27 28 initial 29 clk = 1'b0; 30 always #10 clk = ~clk; 31 32 initial 33 begin 34 #1; 35 rst_n = 1'b1; 36 divisor = 28'd3; 37 dividend = 28'd200; 38 #201; 39 rst_n = 1'b0; 40 #1000; 41 42 rst_n = 1'b1; 43 divisor = 28'd7; 44 dividend = 28'd300; 45 #201; 46 rst_n = 1'b0; 47 #1000; 48 49 rst_n = 1'b1; 50 divisor = 28'd7; 51 dividend = 28'd800; 52 #201; 53 rst_n = 1'b0; 54 55 56 57 58 #10000000; 59 60 61 62 $finish; 63 end 64 65 endmodule
仿真截图如下:
上述内容摘录于:https://infinite-zh.com/archives/174