基于FPGA的Verilog语言 signed unsigned 运算&&不同位宽运算(无聊的碎碎叨叨)

这篇具有很好参考价值的文章主要介绍了基于FPGA的Verilog语言 signed unsigned 运算&&不同位宽运算(无聊的碎碎叨叨)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 此文以quartus为例,使用Verilog语言简单编写验证。并对常见赋值运算进行介绍,读者可采用附带程序进行验证和理解。

很神奇的一件事,机器运算仅可以完成最简单的“1+1”,而“1+1”在二进制中可以完成不同bit的加减。他是如何实现的呢?

一.最简单的是加法,再加法中不会产生负数,所以直接对应位数相加,加满进一;

二.在减法中,机器也是通过加法来实现的,因为在机器中,负数用对应的补码来表示,并不表示负数。

1、大数减小数

a.(相同位宽减法)例如-8‘d8可以表示为1000_1000,首位表示正负,命名为符号位,1表示负,0表示正。

-8的补码为反码1111_0111(反码)加一,即1111_1000(补码)。

1111_0111(反码)+0000_0001=1111_1000(补码)

让我们来计算一下10-8(8bits),

0000_1010(10)
- 0000_1000(8)
0000_0010(2)

 如果我们把-8写为补码1111_1000,则此时应该为10+(-8)

0000_1010(10)
+ 1111_1000(-8补码)
1_0000_0010

可见此时,计算结果溢出第九位,按8bits截取结果依然正确。

b.(不同位宽减法)在不同位宽的计算中,显然加法不会出现问题,减法直接用源码去计算也不会出现问题(如果计算结果大于0),让我们来试一下不同位宽的减法使用补码计算是否还可以成立。8’d8-4'd4

0000_1000(8)
+ _____1100(-4补码)
0001_0100(2)

此时按8bits高位截取发现出现错误。

问题在于短位宽应补齐至高位宽(按首位补),计算如下

0000_1000(8)
+ 1111_1100(-4补码)
1_0000_0100(2)

c1(signed) = a(unsigned) - b(unsigned)

verilog不同位宽的数据之间的运算,fpga开发

2.不妨让我们顺便试一下小数减大数

 a.相同位宽操作8‘d4-8'd6,我们先采用源码计算

0000_0100(4)
- 0000_0110(6)

 此时发现会被无限借位。

如果我们采用补码计算,

0000_0100(4)
+ 1111_1010(-6补码)
1111_1110(-2补码)

 此时计算正确。

c1(signed) = a(unsigned) - b(unsigned)

verilog不同位宽的数据之间的运算,fpga开发

 c(unsigned) = a(unsigned) - b(unsigned)

verilog不同位宽的数据之间的运算,fpga开发

 在仿真中,不管我们是否定义结果是否赋值为符号值,都默认算出补码。但是未声明符号值的结果将被视为1_1111_1110(510),如果再继续进行计算将出现错误。

b.我们再来试一下不同位宽的小数减大数,8‘d4-4'd6

0000_0100(4)
+ 1111_1010(-6补码)
1111_1110(-2补码)

 如果我们按最高位补位计算可以顺利进行。所以在机器计算中,默认负数以补码存在。

 三,Verilog 运算中只要出现无符号位,此式按无符号位运算

Verilog 运算中只要出现无符号位,此式按无符号位运算,这句话经常看到,但是我们将无符号位的两个数相减,赋值给带符号为的值,例如c1(signed) = a(unsigned) - b(unsigned),由仿真结果来看,计算结果还是正确的,但是此时机器存储的并不认为是补码,而是源码,继续计算就会出错。所以我们尽可能的避免混用。

这句话用来描述逻辑运算会更适合。这就要提及较为简单而又interesting的比较器。

如果我们将无符号值与有符号值进行比较大小,此时会出现很大问题,因为这个运算将按无符号位计算,然而在负数中,机器以补码的方式存储,如果将补码视为源码,将是很大的正值。

例如,8'd6 与 -8’d2

6 < -2
0000_0110 < 1111_1110

例如,-8'd6 与 -8’d2

-6 < -2
1111_1010 < 1111_1110

在比较时,出现负数如何进行比较呢?

我们建议使用parameter signed   L0=1‘b0;先定义被比较值为符号值。

                            reg    signed   [7:0]  c1

                            if( c1 >=   L0


下面为.v文件,可直接复制。

module signed_1(
input   							 clk,
input     						   rst_n,
input   wire  unsigned	[7:0] 	       a,
input   wire  unsigned	[7:0]	       b,
input   wire  signed 	[4:0]		  a1,
input   wire  signed 	[8:0]		  b1,
output  reg   unsigned  [9:0]		   c,
output  reg   signed    [8:0]		   c1
);
 
 parameter    signed         x0='d0;
 always @(posedge clk or negedge rst_n)
	begin
	 if (!rst_n)begin
	  c1 <= 'd0;
	  c  <= 'd0;end
	  
	  else if (a1  >  x0)
	  c1 <= 'd1;
	  else if (a1  <  x0)
		 c1 <=(a1);
	end
endmodule 

 下面为测试仿真文件,可借助modelsim进行仿真验证。文章来源地址https://www.toymoban.com/news/detail-694870.html

`timescale 1ns/1ns
module signed_1_tb();
			reg                       clk		   ;
			reg			              rst_n		   ;
			wire  unsigned [7:0]         a         ;
			wire  unsigned [7:0]         b         ;
			wire  signed   [4:0]         a1        ;
			wire  signed   [8:0]         b1        ;
			wire  unsigned [9:0]         c         ;
			wire  signed   [8:0]         c1        ;
			     
 unassign a  = 8'd8;
 unassign b  = 8'd5;
 assign a1 = -5'd8;
 assign b1 = 9'd5;	 
		
				
				
		initial 
				begin
				 clk  =  1'b0;
				 #3000   $stop;
				end
			always #10   clk = ~clk;
			
		initial 
				begin
				 rst_n 	=	1'b0;
				 #80  rst_n  =  1'b1;
				end	
				
signed_1 signed_0(
.clk   (clk   ),
.rst_n (rst_n ),
.a     (a     ),
.a1    (a1    ),
.b     (b     ),
.b1    (b1    ),	
.c     (c     ),
.c1    (c1    )
);		
				
endmodule	

到了这里,关于基于FPGA的Verilog语言 signed unsigned 运算&&不同位宽运算(无聊的碎碎叨叨)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包