基于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)

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)

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

 在仿真中,不管我们是否定义结果是否赋值为符号值,都默认算出补码。但是未声明符号值的结果将被视为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进行仿真验证。

`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	

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值