此文以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<-20000_0110<1111_1110

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

-6<-21111_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

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: