(原创)采用加法器数乘法器实现17位有符号数相乘(Verilog)
2010-07-27 17:17
405 查看
本例程采用加法器数乘法器实现17位有符号数相乘。参考《基于Verilog HDL 的数字系统应用设计》,王钿 ,桌兴旺 编著
调试小结:本例程采用了5级流水线技术,以至于能在一个时钟周期内完成一次乘法运算输出。参考的范例为4位无符号输入,采用2级流水线技术。
由于是有符号运算,符号位要单独处理,也就是把两个数的最高位相异或,即可得到乘积的符号位。如:
有符号数是以补码形式存放在内存的,所以必须要将补码转换为原码后再进行运算,运算后的结果再根据乘积符号位判断最终结果是正还是负,若为负,还需将运算后的结果还原为补码,之后加入一位符号位,便可得到33位的有符号最终结果。(无论是整数还是小数都适用)
由于采用流水线技术,所以有可能会出现时序不一致,该例程出现的问题就是符号位的运算和数据位的运算时序不一致,所以添增了几层赋值运算,确保二则时序一致,不然将会运算出错。
本例程只用了一个always,里面有很多的运算,最初,我心里想,我在一个always里面进行那么多的运算,一个时钟周期怎么能处理完呢,如果一个时钟周期处理不完,那么不是有些变量的值会丢失吗,最初没有调试成功,我一直都怀疑是这个原因,所以我就把always里的每一个运算都单独拿出来,放到一个always里面,也就是每个always里只有一个运算,一共写了好几十个always,程序写得相当的长,但问题还是没有解决,然后再一次仔细研究,才发现是符号位运算的时序跟数据位运算不一致,所以就想办法延时符号位运算结果送至最终乘积结果的时间,现在想出的办法是多加几层的赋值,来拖延符号运算结果送至最终乘积结果的时间。这时才发现,原来我一直没有搞明白always是怎样一步一步执行的,现在明白了,时钟触发always语句里面一般都用非阻塞赋值,非阻塞赋值就是第二个赋值语句,不需要等待第一个赋值语句完成后才进行,这样的结果是,第二个赋值语句不能以第一个语句的最新结果参与运算,而是以前一状态的值参与运算。他们几乎是同时进行的,也就是在每个时钟内,always里面的语句都将执行一次,不存在一个时钟内,有些语句还未执行到。最初,我学Verilog的时候就把非阻塞语句和阻塞语句区别开了的,但似乎并没有真正理解并会应用。我为这个,付出了很多很多,现在终于解决了!
改正一处:
原来:
更改为:
更改原因:当输入的两个数,一个为0,另一个为负数时,按原来的代码运算乘积并不是0,而是-1,所以需要改正,改正后不会出现这样的错误。
module signed_mult17b_addtree ( mul_a, mul_b, mul_out, clk, rst_n, ); parameter MUL_WIDTH = 17; parameter MUL_RESULT = 33; input [MUL_WIDTH-1:0] mul_a; input [MUL_WIDTH-1:0] mul_b; input clk; input rst_n; output [MUL_RESULT-1:0] mul_out; reg [MUL_RESULT-1:0] mul_out; reg [MUL_RESULT-1:0] mul_out_reg; reg msb; reg msb_reg_0; reg msb_reg_1; reg msb_reg_2; reg msb_reg_3; reg [MUL_WIDTH-1:0] mul_a_reg; reg [MUL_WIDTH-1:0] mul_b_reg; reg [MUL_RESULT-2:0] stored0; reg [MUL_RESULT-2:0] stored1; reg [MUL_RESULT-2:0] stored2; reg [MUL_RESULT-2:0] stored3; reg [MUL_RESULT-2:0] stored4; reg [MUL_RESULT-2:0] stored5; reg [MUL_RESULT-2:0] stored6; reg [MUL_RESULT-2:0] stored7; reg [MUL_RESULT-2:0] stored8; reg [MUL_RESULT-2:0] stored9; reg [MUL_RESULT-2:0] stored10; reg [MUL_RESULT-2:0] stored11; reg [MUL_RESULT-2:0] stored12; reg [MUL_RESULT-2:0] stored13; reg [MUL_RESULT-2:0] stored14; reg [MUL_RESULT-2:0] stored15; reg [MUL_RESULT-2:0] add0_0; reg [MUL_RESULT-2:0] add0_1; reg [MUL_RESULT-2:0] add0_2; reg [MUL_RESULT-2:0] add0_3; reg [MUL_RESULT-2:0] add0_4; reg [MUL_RESULT-2:0] add0_5; reg [MUL_RESULT-2:0] add0_6; reg [MUL_RESULT-2:0] add0_7; reg [MUL_RESULT-2:0] add1_0; reg [MUL_RESULT-2:0] add1_1; reg [MUL_RESULT-2:0] add1_2; reg [MUL_RESULT-2:0] add1_3; reg [MUL_RESULT-2:0] add2_0; reg [MUL_RESULT-2:0] add2_1; reg [MUL_RESULT-1:0] add3_0; always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) begin mul_a_reg <= 17'b0; mul_b_reg <= 17'b0; stored0 <= 32'b0; stored1 <= 32'b0; stored2 <= 32'b0; stored3 <= 32'b0; stored4 <= 32'b0; stored5 <= 32'b0; stored6 <= 32'b0; stored7 <= 32'b0; stored8 <= 32'b0; stored9 <= 32'b0; stored10 <= 32'b0; stored11 <= 32'b0; stored12 <= 32'b0; stored13 <= 32'b0; stored14 <= 32'b0; stored15 <= 32'b0; add0_0 <= 32'b0; add0_1 <= 32'b0; add0_2 <= 32'b0; add0_3 <= 32'b0; add0_4 <= 32'b0; add0_5 <= 32'b0; add0_6 <= 32'b0; add0_7 <= 32'b0; add1_0 <= 32'b0; add1_1 <= 32'b0; add1_2 <= 32'b0; add1_3 <= 32'b0; add2_0 <= 32'b0; add2_1 <= 32'b0; add3_0 <= 32'b0; msb <= 1'b0; msb_reg_0 <= 1'b0; msb_reg_1 <= 1'b0; msb_reg_2 <= 1'b0; msb_reg_3 <= 1'b0; mul_out_reg <= 33'b0; mul_out <= 33'b0; end else begin mul_a_reg <= (mul_a[16]==0)? mul_a : {mul_a[16],~mul_a[15:0]+1'b1}; mul_b_reg <= (mul_b[16]==0)? mul_b : {mul_b[16],~mul_b[15:0]+1'b1}; msb_reg_0 <= mul_a_reg[16] ^ mul_b_reg[16]; msb_reg_1 <= msb_reg_0; msb_reg_2 <= msb_reg_1; msb_reg_3 <= msb_reg_2; msb <= msb_reg_3; stored0 <= mul_b_reg[0] ? {16'b0,mul_a_reg[15:0]} : 32'b0; stored1 <= mul_b_reg[1] ? {15'b0,mul_a_reg[15:0],1'b0} : 32'b0; stored2 <= mul_b_reg[2] ? {14'b0,mul_a_reg[15:0],2'b0} : 32'b0; stored3 <= mul_b_reg[3] ? {13'b0,mul_a_reg[15:0],3'b0} : 32'b0; stored4 <= mul_b_reg[4] ? {12'b0,mul_a_reg[15:0],4'b0} : 32'b0; stored5 <= mul_b_reg[5] ? {11'b0,mul_a_reg[15:0],5'b0} : 32'b0; stored6 <= mul_b_reg[6] ? {10'b0,mul_a_reg[15:0],6'b0} : 32'b0; stored7 <= mul_b_reg[7] ? {9'b0,mul_a_reg[15:0],7'b0} : 32'b0; stored8 <= mul_b_reg[8] ? {8'b0,mul_a_reg[15:0],8'b0} : 32'b0; stored9 <= mul_b_reg[9] ? {7'b0,mul_a_reg[15:0],9'b0} : 32'b0; stored10 <= mul_b_reg[10] ? {6'b0,mul_a_reg[15:0],10'b0} : 32'b0; stored11 <= mul_b_reg[11] ? {5'b0,mul_a_reg[15:0],11'b0} : 32'b0; stored12 <= mul_b_reg[12] ? {4'b0,mul_a_reg[15:0],12'b0} : 32'b0; stored13 <= mul_b_reg[13] ? {3'b0,mul_a_reg[15:0],13'b0} : 32'b0; stored14 <= mul_b_reg[14] ? {2'b0,mul_a_reg[15:0],14'b0} : 32'b0; stored15 <= mul_b_reg[15] ? {1'b0,mul_a_reg[15:0],15'b0} : 32'b0; add0_0 <= stored0 + stored1; add0_1 <= stored2 + stored3; add0_2 <= stored4 + stored5; add0_3 <= stored6 + stored7; add0_4 <= stored8 + stored9; add0_5 <= stored10 + stored11; add0_6 <= stored12 + stored13; add0_7 <= stored14 + stored15; add1_0 <= add0_0 + add0_1; add1_1 <= add0_2 + add0_3; add1_2 <= add0_4 + add0_5; add1_3 <= add0_6 + add0_7; add2_0 <= add1_0 + add1_1; add2_1 <= add1_2 + add1_3; add3_0 <= add2_0 + add2_1; mul_out_reg <= {msb,add3_0[31:0]}; mul_out <= (mul_out_reg[32]==0)? mul_out_reg : {mul_out_reg[32],~mul_out_reg[31:0]+1'b1}; end end endmodule
调试小结:本例程采用了5级流水线技术,以至于能在一个时钟周期内完成一次乘法运算输出。参考的范例为4位无符号输入,采用2级流水线技术。
由于是有符号运算,符号位要单独处理,也就是把两个数的最高位相异或,即可得到乘积的符号位。如:
msb_reg_0 <= mul_a_reg[16] ^ mul_b_reg[16];
有符号数是以补码形式存放在内存的,所以必须要将补码转换为原码后再进行运算,运算后的结果再根据乘积符号位判断最终结果是正还是负,若为负,还需将运算后的结果还原为补码,之后加入一位符号位,便可得到33位的有符号最终结果。(无论是整数还是小数都适用)
mul_a_reg <= (mul_a[16]==0)? mul_a : {mul_a[16],~mul_a[15:0]+1'b1}; mul_b_reg <= (mul_b[16]==0)? mul_b : {mul_b[16],~mul_b[15:0]+1'b1}; mul_out <= (mul_out_reg[32]==0)? mul_out_reg : {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};
由于采用流水线技术,所以有可能会出现时序不一致,该例程出现的问题就是符号位的运算和数据位的运算时序不一致,所以添增了几层赋值运算,确保二则时序一致,不然将会运算出错。
msb_reg_1 <= msb_reg_0; msb_reg_2 <= msb_reg_1; msb_reg_3 <= msb_reg_2; msb <= msb_reg_3;
本例程只用了一个always,里面有很多的运算,最初,我心里想,我在一个always里面进行那么多的运算,一个时钟周期怎么能处理完呢,如果一个时钟周期处理不完,那么不是有些变量的值会丢失吗,最初没有调试成功,我一直都怀疑是这个原因,所以我就把always里的每一个运算都单独拿出来,放到一个always里面,也就是每个always里只有一个运算,一共写了好几十个always,程序写得相当的长,但问题还是没有解决,然后再一次仔细研究,才发现是符号位运算的时序跟数据位运算不一致,所以就想办法延时符号位运算结果送至最终乘积结果的时间,现在想出的办法是多加几层的赋值,来拖延符号运算结果送至最终乘积结果的时间。这时才发现,原来我一直没有搞明白always是怎样一步一步执行的,现在明白了,时钟触发always语句里面一般都用非阻塞赋值,非阻塞赋值就是第二个赋值语句,不需要等待第一个赋值语句完成后才进行,这样的结果是,第二个赋值语句不能以第一个语句的最新结果参与运算,而是以前一状态的值参与运算。他们几乎是同时进行的,也就是在每个时钟内,always里面的语句都将执行一次,不存在一个时钟内,有些语句还未执行到。最初,我学Verilog的时候就把非阻塞语句和阻塞语句区别开了的,但似乎并没有真正理解并会应用。我为这个,付出了很多很多,现在终于解决了!
改正一处:
原来:
mul_out_reg <= {msb,add3_0[31:0]}; mul_out <= (mul_out_reg[32]==0)? mul_out_reg : {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};
更改为:
mul_out_reg <= (add3_0==0)? 33'b0 : {msb,add3_0[31:0]}; mul_out <= (mul_out_reg==0)? 33'b0 : (mul_out_reg[32]==0)? mul_out_reg : {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};
更改原因:当输入的两个数,一个为0,另一个为负数时,按原来的代码运算乘积并不是0,而是-1,所以需要改正,改正后不会出现这样的错误。
相关文章推荐
- [转载]采用加法器数乘法器实现17位有符号数相乘(Verilog)
- [原创]采用SocketAsyncEventArgs实现异步UDP收发
- (原创)用verilog实现RGB格式图像到YCbCr或YUV格式的转换及其验证方法 (RGB2YCrCb)(RGB2YUV)
- verilog 实现无符号整数除法运算
- 【原创】10万条数据采用存储过程分页实现(Mvc+Dapper+存储过程)
- 用verilog实现有符号数的加法
- (原创)如何进行有符号小数乘法运算?(Verilog)
- verilog中有符号整数说明及除法实现
- C++实现堆排序并记录编程中遇到的一个bug(不要对无符号整形数在--的循环中采用>=0作为结束条件)
- 用Verilog实现视频信号的检测(采用外部低频时钟)
- wpf采用Xps实现文档显示、套打功能(原创)
- 用宏定义实现注释符号
- C语言字符串反转实现【采用头指针和尾指针方法完成】
- opencv 矩阵与一个常数相乘的 两种实现方法
- FPGA中用verilog分频实现方法
- [原]【原创】无锁编程技术及实现
- 采用软件负载均衡器实现web服务器集群(iis+nginx)
- java数据结构-图的实现 采用数组和邻接矩阵
- 采用Memcached实现分布式Session
- List<T>采用delegate快速实现排序、查找等操作