Verilog中的有符号计数,一般是自己定义的而不是像C语言之类的定义一个有符号变量就好了。所以,要想在FPGA的世界里随心所欲的进行有符号运算,必须先对补码有一个很好的认知,然后再注意Verilog中编程的几个特性,两者缺一不可。

  对补码初步的认识:

  1、正数的补码与源码相同,即正数的补码是其本身。

  2、负数的补码,是对其源码(除符号位)取反再加一,于是得到其补码。

  3、对负数的补码(除符号位)取反再加一,于是得到其源码。

  4、正数的补码被定义为其本身,所以不需以上操作。(其实你也可以理解为正数没有补码)

  5、“计算机”储存数时是以补码的形式储存的。

  以四位二进制举例(最高位是其符号位):

  -7,负7的源码:1_111;

  -7,负7的补码:1_001;

  在此提出一个看法,帮助理解,补码是给计算机看的,源码是给人看的。

  看看1 + (- 2) 如何计算,我们知道负数的话都是由补码储存的所以就是1 + (-2的补码),及

0_001 + 1_110 = 1_111;(最高为为符号位),所以1111及-1的补码(对负数的补码(除符号位)取反再加一,于是得到其源码)

  这给我们了一个启示,前面说过“Verilog中的有符号计数,一般是自己定义的”,那么在写Verilog时我们把最高为作为符号位,我们通过最高位判断该数的正负。

对于FPGA的有符号计算,我觉得应该从两种情况进行分析。一种是:输入的两个数本来是无符号的,而由于运算导致结果是一个有符号的数(如1-7=-6);

另一种是:输入的两个数是有符号的。

   对于第一种情况而言,1-7=-6,这个-6会自动以负数补码的形式储存在你声明的寄存器中。举一个例子:

input [:]A,
input [:]B,
output reg [:]Result

A,B作为两个运算的数,Result储存运算的结果,他们的最高位都是表示符号位。

假如:A = 0001,B = 0111;让A-B,那么1-7=-6及Result = 1010(-6 的补码,最高位是符号位),没有问题。

假如:A = 0111,B = 0111;让A+B,那么7+7=14及Result = 1110;此时如果最高位不是符号位那么Result=14没错,但是此时Result的最高为是符号位,所以结果是-1(1110是-1的补码)。

也就是,一旦产生了进位,结果就错了。所以我们改进一下。

input [:]A,
input [:]B,
output reg [4:]Result

我们把Result增加一位,那么7+7=14及Result = 01110;这样就对了;但是1-7,Result = 01010 = 10;这就错了。因为对于一个4位数

而言-6 的补码是1010,而对于一个5位数而言-6 的补码是11010。所以Result = 11010才对,但是A和B是一个4位数结果只会产生1010而赋值

给一个5位数的Result结果只能是01010(系统是不会帮你把最高位置1的);所以这个1由我们自己置,正所谓,自己动手丰衣足食。对于补码而言

还有一个特性,只要确定该数是一个负数的补码,那么不管我们在符号位前面放置多少个1该数的值不变(但记住最高为始终是符号位),这类似与

一个正数前不管加多少个0它的值不变。举个例子1_010,表示-6的补码,那么1111111_010仍然是-6的补码。所以当我们判断该数是一个负数

补码的话,我们就可以安心的给最前面加个1了。

  对于第一种情况而言,我们可以把程序写成这样:

module Test
(
input CLK ,
input RSTn,
input [:]A,
input [:]B,
output reg [:]Result
); reg [:]i;
reg [:]TempRes;//中间结果
always @(posedge CLK or negedge RSTn)
if(!RSTn) begin Result <='d0; i <= 2'd0; TempRes <= 'd0; end
else
case(i)
          0:i <= i + 1'b1;
://求出A+B的结果
begin
              Result <= A + B;
i <= i + 'b1;
end
2://求出A-B的结果
begin
              TempRes <= A - B;
Result <= TempRes[4] ? {1'b1,TempRes} : TempRes;
i <= i + 1'b1;
            end 
        endcase endmodule

这样的话,运算时不管是产生借位或是进位,都不会出错了,但前提是“第一种情况”——A,B都是无符号的数。现在我们反过来想想,为什么我要把Result扩充一位,

原因就是,为了避免产生进位是进位位会覆盖符号位,因为对于一个有符号的4位数他的表示的正数范围是0到7(呵呵,暂时把0划归到正数吧,这样平衡一些),负数范围是-8到-1。

而对与第一种情况而言,能产生的最大数就是是0111 + 0111 = 1110这种情况,也就是说进位位不可能威胁到符号位,从而确保了最高位只可能表示符号位。

以上程序可以写一个测试程序仿真,0:i <= i + 1'b1;这个是为了缓冲一个时钟周期,用于A,B信号的输入。测试程序如下:

initial
begin
RSTn = ; #; RSTn = ;
CLK = ; forever # CLK = ~CLK;
end always @(posedge CLK or negedge RSTn)
if(!RSTn)begin A <= 'd0; B <= 0; end
else begin A <= -; B <= ;end

  接下来讨论一下,第二种情况——输入的两个数是有符号的;(第一种情况其实是比第二种情况多见。)

这个请况比较麻烦,需要再次细分成几种小情况:

程序如下:

 module Test
(
input CLK ,
input RSTn,
input [:]A,
input [:]B,
output reg [:]Result
); reg [:]i;
reg [:]TempRes;//中间结果
always @(posedge CLK or negedge RSTn)
if(!RSTn) begin Result <='d0; i <= 2'd0; TempRes <= 'd0; end
else
case(i)
:i <= i + 'b1;
://求出A+B的结果
begin
if(A[] == )//A为负数的情况----------------------------
begin
if(B[] == ) //B为负数
Result <= ~{'b0,(~A + 1'b1 + ~B + 'b1)} + 1'b1;
else //B为正数
begin
TempRes = B + A;//TempRes = B - (~A + 1'b1);
Result <= TempRes[] ? {'b1,TempRes} : TempRes;
end
end
else //A为正数的情况----------------------------
begin
if(B[] == ) //B为负数
begin
TempRes = A + B;//TempRes = A - (~B + 1'b1);
Result <= TempRes[] ? {'b1,TempRes} : TempRes;
end
else //B为正数
Result <= A + B;
end
i <= i + 'b1;
end
://求出A-B的结果
begin
if(A[] == ) //A为负数的情况----------------------------
begin
if(B[] == ) //B为负数
begin
TempRes = (~B + 'b1) + A;//TempRes = (~B + 1'b1) - (~A + 'b1);
Result <= TempRes[] ? {'b1,TempRes} : TempRes;
end
else //B为正数
Result <= ~{'b0,(~A + 1'b1 + B)} + 'b1;
end
else //A为正数的情况----------------------------
begin
if(B[] == ) //B为负数
//Result <= A + (~B + 1'b1);//不知道为什么,这样Result最高位会被置1????!!!!!!
Result <= {'b0,A - B};//Result <= {1'b0,A + (~B + 'b1)};
else //B为正数
begin
TempRes <= A - B;
Result <= TempRes[] ? {'b1,TempRes} : TempRes;
end
end
end
endcase endmodule

要理解上面程序,首先理解这一句:

Result <= ~{1'b0,(~A + 1'b1 + ~B + 1'b1)} + 1'b1;

这种情况是A,B都为负数,A - B的情况,A和B都是负数补码,所以~A + 1'b1这样的操作就是将负数补码变成正数。将他们全变成正数后相加后,变成负数补码的形式,储存在Result中。类似于 -3 + -5 = -(3 + 5) = -8;

 其他情况,自行分析。至于57行不能写成那样,是什么原因还不清楚,知道的朋友请告诉我一声,先谢谢了。

//----------------------------------------------------------------------------------------------------------------------------------------

对了,要补充一点,之前分析到:对于一个有符号的4位数他的表示的正数范围是1到7,负数范围是-8到-1。

多多少少也感觉到一定不平衡,正数能表示到7,而负数却能表示到-8。接就是1000~0111;-8~7这么个范围。

根据第3条:3、对负数的补码(除符号位)取反再加一,于是得到其源码。

我们把-8的补码去反加1,看看能不能得到正8,结果还是-8.我们来看看过程

1_000 ->取反(除符号位)->1_111-> 加1->1_000;我们再看看如果最高位不是符号位1000正好又是8!

  这个也是补码让人头晕的地方,对于一个5位数也一样1_0000,表示-16,取反加1,还是-16.

  module Test
(
input CLK ,
input RSTn,
input [:]A,
input [:]B,
output reg [:]Result
);

16 - (—16) = 32;而作为Result
而言,它的表示范围是-32到31。
但Result无法表示到32,这不是有问题吗?不是的,因为A和B是无法表示到16的顶多就是-16.所以以上情况不可能出现。

                                              —— 宋桓公
2013-11-04

Verilog中的有符号计算之认知补码的更多相关文章

  1. system verilog中的跳转操作

    在verilog中,使用disable声明来从执行流程中的某一点跳转到另一点.特别地,disable声明使执行流程跳转到标注名字的声明组末尾,或者一个任务的末尾. verilog中的disable命令 ...

  2. system verilog中的类型转换(type casting)、位宽转换(size casting)和符号转换(sign casting)

    类型转换 verilog中,任何类型的任何数值都用来给任何类型赋值.verilog使用赋值语句自动将一种类型的数值转换为另一种类型. 例如,当一个wire类型赋值给一个reg类型的变量时,wire类型 ...

  3. 一段比较有意思的代码——介绍system verilog中的新增幅值语句

    system verilog中新加了很多幅值语句,虽然都只适用于阻塞幅值,但是在某些场合中非常实用. 下面是一段有意思的代码,覆盖了一些用法. package definitions; typedef ...

  4. 关于verilog中if与case语句不完整产生锁存器的问题 分类: FPGA 2014-11-08 17:39 260人阅读 评论(0) 收藏

    在很多地方都能看到,verilog中if与case语句必须完整,即if要加上else,case后要加上default语句,以防止锁存器的发生,接下来就来说说其中原因. 一,什么是锁存器?锁存器与触发器 ...

  5. 关于Verilog 中的for语句的探讨

    在C语言中,经常用到for循环语句,但在硬件描述语言中for语句的使用较C语言等软件描述语言有较大的区别. 在Verilog中除了在Testbench(仿真测试激励)中使用for循环语句外,在Test ...

  6. Verilog中锁存器与多路选择器

    Verilog中锁存器与多路选择器 Verilog是一种硬件描述语言,它代表的是硬件. Verilog代表的就是逻辑门和连接线. 对于一个always@(*)控制的块而言,只要块中的表达式包含的任意的 ...

  7. verilog中always块延时总结

    在上一篇博文中 verilog中连续性赋值中的延时中对assign的延时做了讨论,现在对always块中的延时做一个讨论. 观测下面的程序,@0时刻,输入的数据分别是0x13,0x14 . @2时刻, ...

  8. verilog中读取文件中的字符串_modelsim高级仿真

    今天给个程序大家玩玩.因为今天遇到一个问题,就是要向UART发送指令,指令非常多,都是字符串.一直copy 函数 UART ("COMM_1");  UART ("COM ...

  9. verilog中的有符号数运算

    verilog中的有符号数运算 http://hi.baidu.com/lixu1113/item/d00dc095f86aed48f142159a verilog中的有符号数运算 有符号数的计算:若 ...

随机推荐

  1. Android Design Support Library(三)用CoordinatorLayout实现Toolbar隐藏和折叠

    此文的代码在Android Design Support Library(一)用TabLayout实现类似网易选项卡动态滑动效果代码的基础上进行修改,如果你没有看过本系列的第一篇文章最好先看一看.Co ...

  2. Apache,PHP,MySQL独立安装

    最近在工作中常常接触到PHP,自己也写过一些简单的PHP页面.我们知道PHP是在服务器端运行的脚本语言,因此我们需要配置服务器环境.之前为了省事直接使用的是wamp集成环境,但是突然某一天领导要求我们 ...

  3. webservice安全性浅谈

    原文地址:http://www.cnblogs.com/chhuic/archive/2009/11/19/1606109.html 做项目时,经常会用到WebService来通讯,但WebServi ...

  4. USB 相关笔记

    1分析已有代码项目 Android从USB声卡录制高质量音频-----使用libusb读取USB声卡数据 github 项目:usbaudio-android-demo usb声卡取数据项目也是参考的 ...

  5. length() 用法

    length:(字符串 | 列):求出字符串的长度: 求出bqh4表中zym列的长度. select * from bqh4select a.*,length(zym) from bqh4 a

  6. [Redis_1] Redis 介绍 && 安装

    0. 说明 Redis 介绍 && 安装 1. Redis 介绍 2. Redis 安装(Windows 10) [2.1 解压 redis-2.2.2-win32-win64.rar ...

  7. [WPF]启动参数

    在App.xaml.cs中重写方法OnStartup protected override void OnStartup(StartupEventArgs e) { //e.Args为命令行参数 // ...

  8. EXI6.0的安装(找不到网卡、找不到磁盘)

    给一台华为2488 V5 服务器安装EXI6.0服务 (问过华为售后不支持EXI5.5的安装,建议EXI6.0及以上版本) 根据界面提示信息按“Del”.进入BIOS设置界面 参考博客地址:https ...

  9. SQL 性能不佳的几个原因

    •不准确的统计数据•差劲的索引•差劲的查询设计 •差劲的执行计划,通常是由不正确的参数引起的•过度阻塞和死锁 •非基于集合的操作•不良数据库设计 •过度碎片 •不能重复使用执行计划 •查询频繁重编译 ...

  10. November 17th, 2017 Week 46th Friday

    If you shut the door to all errors, truth will be shut out. 你如果拒绝面对错误,真相也会被挡在门外. Sometimes being a f ...