分享

divisor详细设计方案

 卤煮小鱼 2015-12-27

 


1.循环型除法器简介:

补码除法器。

2.循环型除法器规格:

八位循环型除法器。

3.实现原理

首先我们看小学时代的一个公式:被除数     =除数   X    +余数

应因小学我们没学过负数,这里假定被除数与除数都是自然数。能不能

为负数呢?下面在说。

循环型触发器的原理其实也很简单就是:判断被除数有多少个除数,满

足的条件是商小于除数。如果用  C语言写的话

Q  =  0;

while(rmin   <<  dsor)

{

rmin  =  rmin   –  dsor;

Q  ++;

}

这里它们都是正数哈,则计算的结果:  Q是商,rmin是余数。

但是我们发现,当 rmin     dsor大小不一样时,计算所花费的步骤将不

一样,这里我们要做的是一个,时钟消耗一样的除法器。

假设

被除数 A,除数 B,商 Q=Q3    Q2  Q1  Q0,余数 R都是四位二进制数

A-Bx2^3=R  >= 0 ?

A-Bx2^2=R  >= 0 ?

A-Bx2^1=R  >= 0 ?

A-Bx2^0=R>=  0 ?

Q3=1

Q2=1

Q1=1

Q0=1

下一操作  A=R

下一操作  A=R

下一操作  A=R

下一操作  A=R

Q3=0

Q2=0

Q1=0

Q0=0

下一操作 A不变

下一操作 A不变

下一操作 A不变

下一操作 A不变


 

 

1

A=10B=3;

10  –  3  x  2^3  =  -14   <  0

10  –  3  x  2^2  =  -2     <  0

Q3=0

Q2=0

Q1=1

Q0=1

10  –  3  x  2^1  =  4

–  3  x  2^0  =  1

>  0

>  0

则商 Q=1100=3余数    R=1

其实就是

第一步:判断 Q3是否为一,  Q3是第四位权重为   2^3=8。为一的话说明

A至少有  8  B,即 A   –  8B  >=  0,并把余数  R赋给  A进行下一步操作  ;

第二步:判断 Q2是否为一,  Q2是第四位权重为   2^2=4。为一的话说明

A至少有  4  B,即 A   –  4B  >=  0,并把余数  R赋给  A进行下一步操作  ;

第三步:判断 Q1是否为一,  Q1是第四位权重为   2^1=2。为一的话说明

A至少有  2  B,即 A   –  2B  >=  0,并把余数  R赋给  A进行下一步操作  ;

第三步:判断 Q1是否为一,  Q1是第四位权重为   2^0=1。为一的话说明

A至少有  1  B,即 A   –  B  >=  0,并把余数 R赋给   A进行下一步操作  ;

思考中……

Veirlog算法分析:

值得注意的是我们发现  A-Bx2^3=R公式中在每一操作中       A在变,Bx2^

3也在变。我们希望恒数多一点,

2

A=10B=3;

2^0  x    10

2^1  x    10

2^2  x    10

2^3  x    4

3  x  2^3

3  x  2^3

3  x  2^3

3  x  2^3

=

=

=

=

-14  <  0

<  0

16  >  0

>  0

Q3=0

Q2=0

Q1=1

-4

8

Q0=1

则商 Q=1100=3余数    R  /  2^3=1

我们将例 1中的等式分别乘于     1  2  4  8,就能发现被减数不变了。

核心代码:

4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8     :

begin

temp  =   ospace  +  {divisor_n,7'd0};

if(temp[15])   ospace  <=   {ospace[14:0],1'b0};

else  ospace   <=  {temp[14:0],1'b1};

i  <=  i  +  1'b1;

//  divisor   *  2^7

end

因为被除数除数均为  8位二进制数所以操作次数为    8次。

temp  =   ospace  +  {divisor_n,7'd0};

相当于上面的   A-Bx2^3=R只不过是    Bx2^3变成了   8而已。

if(temp[15])   ospace  <=   {ospace[14:0],1'b0};

else  ospace   <=  {temp[14:0],1'b1};

 

 


 

 

判断余数的正负 temp[15]为符号位,这里就不在细解了位操作了,慢慢

消化下面的代码就通了。

算法是活的,代码也是活的,只要抓到老鼠的(结果正确),吃饭少的

(资源消耗小)都是好猫。

差点忘了:

正负数的处理了:在带余数除法中,我们习惯将被除数与除数都化为正

数来计算。得出的余数应与被除数同号。

余数可以为负数吗??带余除法定理不是规定余数恒正??纳尼    ~~~~~

大家可以在仿真看$display输出。

我的另一篇文章对带余除法进行了一定的探讨,是我的想法,如果其中

有什么不对的,多多指教哈。

资源消耗:

仿真结果:

4.  Verilog HDL源代码


 

 

Verilog  HDL代码为:

module divisor

(

//system

input clk ,

input rst_n ,

//

input[7:0] divisor ,

input[7:0] dividend ,

//除数

//被除数

output[7:0] quotient ,      //

output[7:0] reminder ,      //余数

//signe

input start ,

output done

);

reg[15:0] ospace ;      //操作空间

reg[15:0] temp ;

reg[8:0] divisor_n ;    //divisor的负数

reg neg ;

reg neg1;

reg done_r ;

reg[3:0] i ;

always @(posedge clk or negedge  rst_n)

if(!rst_n)

begin

ospace <= 16'd0 ;

temp <= 16'd0 ;

divisor_n <= 8'd0 ;

neg <= 1'b0 ;

neg1 <= 1'b0 ;

done_r <= 1'b0 ;

i <= 4'd0;

end

else if(start)

case(i)

4'd0

:

 

 


 

 

begin

neg <= dividend[7] ^ divisor[7] ;

neg1 <= dividend[7];

ospace <= dividend[7] ? {8'd0,(~dividend + 1'b1)} : {8'd0, dividend};

divisor_n <= divisor[7] ? {1'b1 ,divisor} : {1'b1 ,(~divisor + 1'b1)};

i <= i + 1'b1;

end

4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8  :

begin

temp = ospace + {divisor_n,7'd0};      // divisor * 2^7

if(temp[15]) ospace  <= {ospace[14:0],1'b0};

else ospace <= {temp[14:0],1'b1};

i <= i + 1'b1;

end

4'd9 :

begin

done_r <= 1'b1;

i <= i + 1'b1;

end

4'd10 :

begin

done_r <= 1'b0;

i <= 4'd0;

end

default : i <= 4'd0;

endcase

assign quotient = neg ?    (~ospace[7:0]+1'b1) : ospace[7:0];

assign reminder = neg1 ? (~ospace[15:8]+1'b1) : ospace[15:8];

assign done = done_r;

endmodule

仿真代码为:

`timescale  1 ns/ 1 ps

module divisor_vlg_tst();

reg clk;

reg [7:0] dividend;

reg [7:0] divisor;

reg rst_n;

reg start;

// wires

 

 


 

 

wire done;

wire [7:0]

wire [7:0]

quotient;

reminder;

// assign statements  (if any)

divisor i1 (

.clk(clk),

.dividend(dividend),

.divisor(divisor),

.done(done),

.quotient(quotient),

.reminder(reminder),

.rst_n(rst_n),

.start(start)

);

initial

begin

rst_n = 1'b0;

clk = 1'b1;

#20 rst_n = 1'b1;

$display("%d\n",-4/3);

$display("%d\n",-4%3);

$display("%d\n",4/-3);

$display("%d\n",4%-3);

$display("%d\n",-2/-120);

$display("%d\n",-2%-120);

forever

#10 clk = ~clk;

end

reg[3:0] i;

always @(posedge clk or negedge  rst_n)

if(!rst_n)

begin

dividend <= 8'd0;

divisor <= 8'd0;

start <= 1'b0;

i <= 4'd0;

end

else

case(i)

4'd0 :

begin

 

 


 

 

if(done) begin    start <= 1'b0; i <= i + 1'b1;

end

else begin    dividend <= 8'd125; divisor <= 8'd11; start<=1'b1;

end

end

end

4'd1 :

begin

if(done) begin    start <= 1'b0; i <= i + 1'b1;

end

else begin    dividend <= 8'd158; divisor <= 8'd18;  start<=1'b1;

end

4'd2 :

begin

if(done) begin    start <= 1'b0; i <= i + 1'b1;

end

else   begin    dividend  <=  8'd254;   divisor  <=  8'd136;   start<=1'b1;

end

end

4'd3 :

begin

if(done) begin    start <= 1'b0; i <= i + 1'b1;

end

else begin    dividend <= 8'd248; divisor <= 8'd77; start<=1'b1;

end

end

4'd4 :

begin

if(done) begin    start <= 1'b0; i <= i + 1'b1;

end

else begin    dividend <= 8'd17; divisor <= 8'd18; start<=1'b1;

end

end

4'd5 :

begin

if(done) begin    start <= 1'b0; i <= i + 1'b1;

end

else begin    dividend <= 8'd125; divisor <= 8'd11; start<=1'b1;

end

end

4'd6 : $stop;

default : i <= 4'd0;

endcase

endmodule

5.日积月累

Xxx

6.综合出的电路

xxxx代码综合出的电路如下:

 

 


 

 

2013-8-18

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多