原创 [博客大赛]16位乘法器实验

2013-7-31 14:28 1241 17 17 分类: FPGA/CPLD 文集: FPGA学习过程

今天半想半参考的写完了一个16位乘法器,整个过程还算简单,代码最主要的部分就是移位计算的部分。
在写的过程中,最开始的一次移位部分的代码只有
/*-----------------------------------------------------------------------------------------
gen the yout signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        yout <= 32'd0;
    else if ( cnt == 5'd1 )                     //start拉高结束后一时钟周期内清零yout
        yout <= 32'd0;
    else if ( cnt > 5'd1 && cnt < 5'd18 )       //cnt为1~16进行移位计算(最高位在下边另行计算)
    begin
        if ( breg[cnt-2] )                      //移位且累加
            yout <= {yout[31:16]+areg,yout[15:1]};
        else                                    //只移位
            yout <= yout >> 1;
    end
    else
        yout <= yout;
end
经过波形仿真发现,在位数低的情况下都是正确的,但被乘数上的最高位为1时总会出错,说明在最高位的移位操作中出现问题呢。
经过分析,是由于移位相加满足条件会产生进位但yout <= {yout[31:16]+areg,yout[15:1]};中yout[31:16]+areg会在计算结果的yout中的30~15位上相加后(yout满位数为0~31位),本想直接在31位上进位,但运行时却会忽略这种进位,因此应该主动添加进位,因此改进后应该为:yout <= {{1'b0,yout[31:16]}+areg,yout[15:1]};这样就会主动添加了一个空的位,用于收集进位。
所以在会出现进位的情况下,一定要考虑该进位是否会影响运算结果。

最后附上改进后的程序。
/*-----------------------------------------------------------------------------------------
Module Name:    test_mul16.v
File Author:    creation
Finish Time:    2013-07-27
Description:    16位乘法器实验
-------------------------------------------------------------------------------------------
Version         Design      Coding      Simulate        Review      Rel data
V1.0
-------------------------------------------------------------------------------------------
Version         Modified History
V1.0            draft
-----------------------------------------------------------------------------------------*/
`timescale 1ns / 10ps
module test_mul16(
            input       wire            asy_rst         ,//复位
            input       wire            clk             ,//50MHZ晶振
            input       wire            start           ,//开始标志位
            input       wire    [15:0]  ain             ,//16位被乘数
            input       wire    [15:0]  bin             ,//16位乘数
            output      wire    [31:0]  o_yout          ,//输出结果
            output      wire            o_done           //输出标志位
);
/*---------------------------Internal registers and wires--------------------------------*/
/* Register Input Signals */
reg     [15:0]      areg;                   //被乘数寄存器
reg     [15:0]      breg;                   //乘数寄存器
/* Register Output Signals */
reg     [31:0]      yout;                   //输出结果寄存器
reg                 done;                   //输出标志位寄存器
/* internal logic use signals */
reg     [4:0]       cnt;                    //位移位数寄存器
/* ----------------------Logical Implementation------------------------------------------*/
/*-----------------------------------------------------------------------------------------
gen the cnt signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        cnt <= 1'b0;
    else if ( start == 1'b1 )                   //开始标志位拉高时,cnt赋值1,开始移位
        cnt <= 1'b1;
    else if ( cnt >0 && cnt < 18 )              //cnt为1~17时,进行移位计算,18时,拉高done
        cnt <= cnt + 1'b1;
    else                                        //不在1~17范围内时,不是进行移位
        cnt <= 1'b0;                            //计算状态,cnt为0         
end
/*-----------------------------------------------------------------------------------------
gen the areg signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        areg <= 16'd0;
    else if ( cnt == 1'b1)                  //在start拉高结束后一时钟周期内锁存被乘数ain
        areg <= ain;
    else
        areg <= areg;
end
/*-----------------------------------------------------------------------------------------
gen the breg signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        breg <= 16'd0;
    else if ( cnt == 1'b1 )                 //在start拉高结束后一时钟周期内锁存乘数bin
        breg <= bin;
    else
        breg <= breg;
end
/*-----------------------------------------------------------------------------------------
gen the yout signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        yout <= 32'd0;
    else if ( cnt == 5'd1 )                     //start拉高结束后一时钟周期内清零yout
        yout <= 32'd0;
    else if ( cnt > 5'd1 && cnt < 5'd18 )       //cnt为1~16进行移位计算(最高位在下边另行计算)
    begin
        if ( breg[cnt-2] )                      //移位且累加
            yout <= {{1'b0,yout[31:16]}+areg,yout[15:1]};
        else                                    //只移位
            yout <= yout >> 1;
    end
    else
        yout <= yout;
end
/*-----------------------------------------------------------------------------------------
gen the done signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        done <= 1'b0;
    else if ( cnt == 18 )           //cnt为18,时结束计算操作,可以进行读取
        done <= 1'b1;
    else
        done <= 1'b0;
end
assign o_done = done;               //输出结束标志
assign o_yout = yout;               //输出结果
endmodule

文章评论0条评论)

登录后参与讨论
我要评论
0
17
关闭 站长推荐上一条 /2 下一条