热度 17
2013-7-31 14:28
1241 次阅读|
0 个评论
今天半想半参考的写完了一个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 ) //移位且累加 yout = {yout +areg,yout }; else //只移位 yout = yout 1; end else yout = yout; end 经过波形仿真发现,在位数低的情况下都是正确的,但被乘数上的最高位为1时总会出错,说明在最高位的移位操作中出现问题呢。 经过分析,是由于移位相加满足条件会产生进位但yout = {yout +areg,yout };中yout +areg会在计算结果的yout中的30~15位上相加后(yout满位数为0~31位),本想直接在31位上进位,但运行时却会忽略这种进位,因此应该主动添加进位,因此改进后应该为:yout = {{1'b0,yout }+areg,yout };这样就会主动添加了一个空的位,用于收集进位。 所以在会出现进位的情况下,一定要考虑该进位是否会影响运算结果。 最后附上改进后的程序。 /*----------------------------------------------------------------------------------------- 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 ain ,//16位被乘数 input wire bin ,//16位乘数 output wire o_yout ,//输出结果 output wire o_done //输出标志位 ); /*---------------------------Internal registers and wires--------------------------------*/ /* Register Input Signals */ reg areg; //被乘数寄存器 reg breg; //乘数寄存器 /* Register Output Signals */ reg yout; //输出结果寄存器 reg done; //输出标志位寄存器 /* internal logic use signals */ reg 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 ) //移位且累加 yout = {{1'b0,yout }+areg,yout }; 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