今天半想半参考的写完了一个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条评论)
登录后参与讨论