通用的除法器设计

1.在我上一个文章里,记录了我对于基于Booth编码乘法器的学习

对booth基4编码乘法器的符号扩展思考

这篇文章再简要介绍一下自己所想的一个通用除法器的设计

2.先从原理入手,以 8(1000) / 3(0011) 为例,讲解除法的原理,可以概括除法分为俩个阶段,第一个阶段是求解商的整数部分,第二个阶段是求解商的小数部分

在这里假设 被除数为 y , 除数为 x , 商的整数部分为 q, 小数部分为 n, 初始化q,n均为0

2.1 求解整数部分:

        这一阶段很简单,就拿被除数不停地减除数,直到被除数小于除数为止,以 y=8,x=3  y÷x为例

  1.    判断 y ≥ x ?  是 y=y-x=5 , q=q+1=1 ,否则 y=y , 进入第二阶段             
  2.    判断 y ≥ x ?  是 y=y-x=2 , q=q+1=2 ,   否则 y=y , 进入第二阶段          
  3.    判断 y ≥ x ?  是 y=y-x     , q=q+1     ,   否则 y=y , 进入第二阶段   (这一步进入到阶段2)   

2.2 求解小数部分:

         把0010,进行小数位扩充,如果够减则商补1,被除数变为2者的差,如果不够减则商补0,被除数也同样补0,图中的101分别对应小数后边的第1、2、3位,后面的位数也依次类推

        

3.通用除法器代码:被除数和除数的位宽均取8位,商的整数也取8位,小数取8位有效位

//file name : divider.v
//author    : Kong
module divider#(
	parameter DAT_WID = 8,
	parameter DEC_WID = 8,
	parameter INT_WID = 8
)
(
	clk,
	rst_n,
	vld_i,
	dividend,
	divisor,

	quotient,
	decimals,
	done
);
//------------clob2function-----------------//
  function integer logb2;
    input integer depth;
    for(logb2 = 0 ;depth > 1; logb2 = logb2 + 1) begin
      depth = depth >> 1;
    end
  endfunction
//----------------parameter-----------------//
	
	localparam STD_WID = 2							;
	localparam IDLE = 2'd0							;
	localparam INT  = 2'd1							;
	localparam DEC  = 2'd2							;
	localparam DONE = 2'd3							;

//-----------------in/out-------------------//

	input 										clk					;
	input 										rst_n				;
    input                                       vld_i               ;

	input 			[ DAT_WID - 1 : 0]  dividend      ;
	input 			[ DAT_WID - 1 : 0]	divisor		  ;

	output reg	[ INT_WID - 1 : 0] quotient		;
	output reg	[ DEC_WID - 1 : 0] decimals		;
    output reg                     done         ;



//----------------reg/wire------------------//

	reg 		[ DAT_WID - 1 : 0] dividend_r					;
	reg 		[ DAT_WID - 1 : 0] divisor_r					;
	reg 		[ DAT_WID - 1 : 0] quotient_r					;
    reg 		[ DAT_WID - 1 : 0] decimals_r                   ;
    reg 					       div_done		                ;
 


    reg     [ STD_WID - 1 : 0] cur_state					   ;
    reg     [ STD_WID - 1 : 0] nxt_state					   ;
	reg     [	logb2(DAT_WID - 1) :0]		  cnt 		       ;

	wire    [ DAT_WID - 1 : 0] divend_sub_divsor	;


//-----------------main---------------------//

	always @(posedge clk or negedge rst_n) begin
		if(!rst_n)	begin
			cur_state <= IDLE 		 ;
		end
		else begin
			cur_state <= nxt_state ;
		end
	end
	
  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)  begin
      done <= 1'b0     ;
    end
    else begin
      done <= div_done ;
    end
  end
	always @(posedge clk or negedge rst_n) begin
		if(!rst_n)	begin
			cnt <= 'b0			  ;
		end
		else if(cur_state == DEC)begin
			cnt <= cnt + 1'b1 ;
		end
    else begin
      cnt <= 'b0;
    end
	end

	always@(*)begin
			nxt_state = IDLE;
			case(cur_state)
				IDLE: begin 
								if(vld_i)
									nxt_state = INT	 ;
								else 
									nxt_state = IDLE ;
							end 
				 INT:	begin
                if(divend_sub_divsor == 'b0)  begin
                  nxt_state = DONE;
                end
								else if(dividend_r < divisor_r)	begin
									nxt_state = DEC   ;
								end
								else	begin
									nxt_state = INT   ;
								end
							 end	
					DEC: begin
								if(cnt == DEC_WID - 1 )begin
									nxt_state = DONE  ;
								end
								else begin
									nxt_state = DEC   ;
								end
				      	end
					DONE: begin
									nxt_state = IDLE  ;
					end
			endcase
	end

	assign divend_sub_divsor = dividend_r - divisor_r ;

	always @(posedge clk or negedge rst_n) begin
		if(!rst_n)	begin
			dividend_r 		<=	'b0;
			divisor_r  		<= 	'b0;
			quotient_r      <= 	'b0;
			div_done        <=  'b0;
            decimals_r      <=  'b0;
		end
		else begin
			case(cur_state)
				IDLE : begin
          dividend_r 		<=	'b0;
          divisor_r  		<= 	'b0;
          quotient_r    <= 	'b0;
          div_done      <=  'b0;
          decimals_r    <=  'b0;
					if(vld_i) begin
						dividend_r <= dividend;
						divisor_r  <= divisor ;
					end
				end
				INT : begin
						if(dividend_r >= divisor_r) begin
							dividend_r <= divend_sub_divsor ;
							quotient_r <= quotient_r + 1'b1		;
						end
						else begin
							dividend_r    <= dividend_r << 1;
						end
				end
				DEC	:	begin
						if(dividend_r >= divisor_r)	begin
							decimals_r <= {decimals_r[DEC_WID-2 :0],1'b1}       ;
							dividend_r		<= divend_sub_divsor << 1 		    ;
						end
						else begin
							decimals_r <=  {decimals_r[DEC_WID-2 :0],1'b0}      ;	
							dividend_r		<= dividend_r << 1				    ;
						end
					 end
			  DONE : begin
						div_done <= 1'b1 ;
				end	
			endcase
		end	
	end

	always @(posedge clk or negedge rst_n) begin
		if(!rst_n)	begin
			quotient	<= 'b0 	;
			decimals  <= 'b0	;
		end
		else if(div_done)	begin
			quotient <= quotient_r ;
			decimals <= decimals_r ;
		end
	end
endmodule

 4.tb

//file name: divider_tb.v
//author   : Kong
module divider_tb();
// divider Parameters  
parameter DAT_WID  = 8;
parameter DEC_WID  = 8;
parameter INT_WID  = 8;
// divider Inputs
reg   clk;
reg   rst_n;
reg   vld_i;
reg   [ DAT_WID - 1 : 0]  dividend  ;
reg   [ DAT_WID - 1 : 0]  divisor   ;

// divider Outputs
wire  [ INT_WID - 1 : 0]  quotient;
wire  [ DEC_WID - 1 : 0]  decimals;
wire  done;


initial begin
    dividend = 8'd 8    ;
    divisor  = 8'd 2    ;
end

localparam  max = 8'hff;

always @(posedge clk) begin
    if(done)begin
        vld_i  <= 1'b1;
        dat_gen(dividend,divisor);
    end
    else if(vld_i == 1'b1)  begin
        vld_i <= 1'b0;
    end
end

task dat_gen;
    output [DAT_WID - 1 : 0] a  ;
    output [DAT_WID - 1 : 0] b  ;
    begin
    a     = $random%{max} ;
    b     = $random%{max} ;
    end
endtask



initial begin
    rst_n = 0; # 13 rst_n = 1'b1;
    vld_i = 0; #20 vld_i = 1'b1 ;#10 vld_i = 1'b0;
end



initial begin
    clk = 0 ;
end
always #5 clk = !clk;

divider #(
    .DAT_WID ( DAT_WID ),
    .DEC_WID ( DEC_WID ),
    .INT_WID ( DEC_WID ))
 u_divider (
    .clk                     ( clk        ),
    .rst_n                   ( rst_n      ),
    .vld_i                   ( vld_i      ),
    .dividend                ( dividend   ),
    .divisor                 ( divisor    ),

    .quotient                ( quotient   ),
    .decimals                ( decimals   ),
    .done                    ( done       )
);


endmodule

 5.wave:

可以看到当被除数和除数分别为128和42时,128/42=3.0476

商的整数部分为3,小数部分为12÷256=0.469,达到了较高的精度需求

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值