基于FPGA的数字信号处理(5)--Signed的本质和作用

前言

Verilog中的signed是一个很多人用不好,或者说不太愿意用的一个语法。因为不熟悉它的机制,所以经常会导致运算结果莫名奇妙地出错。其实了解了signed以后,很多时候用起来还是挺方便的。

signed的使用方法主要有两种,其中一种是定义一个有符号数变量,例如:

reg 		[3:0] us_a;	//定义无符号数us_areg signed 	[3:0] s_a;	//定义有符号数s_a

这样定义以后,即使是将同一个值 1111 分别赋值给us_a和s_a,它们所表达的数也不同了,无符号数us_a是 15 ,而有符号数 s_a则是 -1 。但是,这个-1和15是人类或者说工具站在如何解释符号位的角度上解读的,在电路底层,它们的值都是一样的1111。所以signed相当于只是规定了如何来解读一个数的最高有效位。

signed还有一个用法是强制转换,把一个无符号数转换为有符号数类型。例如:

reg [7:0] regA;regA = $signed(-4);

这两个是signed的一般语法,而它的本质在我看来只有两点:

  1. 当计算不产生溢出的时候,signed只影响如何将2进制数解读为10进制数;
  2. 当计算产生溢出的时候,signed影响的是如何对高位扩展–无符号数高位扩展0,而有符号数则高位扩展符号位。

计算结果不溢出

来看下面的代码:

`timescale 1ns/1ns
module tb_test();reg 		[3:0] us_a,us_b;	//无符号加数a、加数b
reg signed	[3:0] s_a,s_b;		//有符号加数a、加数b
reg 		[3:0] us_sum;		//无符号和
reg signed	[3:0] s_sum;		//有符号和initial beginus_a = 4'b1001;		//9us_b = 4'b0001;		//1s_a  = 4'b1001;		//-7s_b  = 4'b0001;		//3#10	us_sum = us_a + us_b;	//9+1s_sum  = us_a + us_b;	//9+1
#10	us_sum = us_a + s_b;	//9+1s_sum  = us_a + s_b;	//9+1
#10us_sum = s_a + us_b;	//-7+1s_sum  = s_a + us_b;	//-7+1
#10	us_sum = s_a + s_b;		//-7+1s_sum  = s_a + s_b;		//-7+1end	endmodule

加数a和加数b分别定义成有符号数和无符号数,加数的和也分别定义成有符号数和无符号数,这样一共有2×2×2 =8 种组合。

给a赋值1001(即无符号数 9/有符号数 -7);给b赋值0001(即无符号数 1/有符号数 1),可以看到他们的计算结果都是一样的1010(即无符号数 10/有符号数 -6):

30d65ce02d30b406d9486035e9cf7eba_202404281141671_raw=true

这个结果和预期是一致的。两个二进制数的加法,因为和没有溢出,所以不管是定义成有符号的还是无符号的,它们的结果肯定都一样。原因就是前面说的第一点:

当计算不产生溢出的时候,signed只影响如何将2进制数解读为10进制数;


计算结果溢出

现在将上面的代码改一下,把和改成5位,使他们的结果需要强制溢出(扩宽)到5位,如下:

reg 		[4:0] us_sum;		//无符号和
reg signed	[4:0] s_sum;		//有符号和

仿真结果已经和上面不同了:

image-20240403115924965

前面3种计算的结果仍然没变,但是第4种计算(即两个有符号数相加)的结果从0_1010变成了1_1010,也就是说最高位的符号位扩展了一位。有符号数和无符号数的运算有一个规则:

不管运算结果是有符号数还是无符号数,只要右边运算式中有一个是无符号数,那么运算结果就是无符号数。

也就是说

  • 无符号数 + 无符号数 的结果是 无符号数
  • 有符号数 + 无符号数 的结果是 无符号数
  • 有符号数 + 有符号数 的结果是 有符号数

因为前3种运算中都有 无符号数 参与,所以不管 和 是定义成有符号数还是无符号数 ,它们的结果都是 无符号数,所以会在高位拓展0;而第4种运算则是只有 有符号数 参与,所以它们的结果都会在高位扩展符号位(即1)。

再来看一个例子:

`timescale 1ns/1ns
module tb_test();reg signed 	[1:0] s_a ;
reg 		[1:0] us_a;reg 		[3:0] s_s_a ;
reg 		[3:0] us_us_a;
reg 		[3:0] inv_s_a ;
reg 		[3:0] inv_us_a;initial begins_a  = -1;us_a = -1;s_s_a  = s_a;us_us_a = us_a;inv_s_a  = - s_a;inv_us_a = - us_a;
end	endmodule

仿真结果是这样的:

image-20240403122129280

  • s_a和us_a的赋值都是 -1,实际就是32‘b111···111,位宽只有2位,所以被截断到2’b11。
  • s_s_a是s_a的高位扩展,因为s_a是有符号数,所以高位扩展补符号位1,就从11变成1111;us_us_a是us_a的高位扩展,因为us_a是无符号数,所以高位扩展补0,从从11变成0011。
  • inv_s_a是s_a的数值的相反数,即补码按位取反后再加1,s_a先从11拓展到1111,再取反加1就变成了0001。从十进制的角度看 s_a(11)是 -1,而 inv_s_a是0001(1),符合相反数的关系。
  • inv_us_a是us_a的数值的相反数,即补码按位取反后再加1,us_a先从11拓展到0011,再取反加1就变成了1101。从十进制的角度看 us_a(11)是 3,而 inv_s_a是1101(-3),也符合相反数的关系。

signed的用法

自动扩展位宽

将一个数的位宽扩展,如果不使用signed语法,则首先需要判断其最高位是否为1,如果是则说明是负数,高位需要扩展1;如果不是则说明是正数,那么高位需要扩展0(正数也可直接赋值,因为不使用signed的话工具会自动扩展0),例如:

module test 
(input 		[3 : 0]	in,output 	reg	[4 : 0]	out
);always@(*)
beginif(~in)					//in是正数out = in;			//直接赋值,等价于高位补0 out = {1'b0,in};else					//in是负数out = {1'b1,in};	//高位保护1
endendmodule

如果使用signed就可以直接赋值了,例如:

module test 
(input	signed	[3 : 0]	in,output	signed	[4 : 0]	out
);assign out = in;			//直接赋值,等价于自动判断高位补符号位endmodule

简化运算

考虑两个4bits数的加法,为了防止结果溢出,把和的位宽设定成5bits。假如两个数分别为0101(5)和1100(-4),则二者的和应该为 (5 - 4 = 1),但实际结果为 0101 + 1100 = 10001(-15),二者显然对不上。

在不使用signed的情况下,我们需要做的是把两个加数分别扩展符号位,然后再相加。0101扩展到00101 ,1100扩展到11100,这样二者相加为 01001 + 11100 = 10_0001,因为结果只有5bits,所以会被截断到00001,也就是1,这样结果就能对上了。代码是这样写的:

module test 
(input	[3 : 0]	in1,in2,output	[4 : 0]	out
);assign out = {in1[3],in1} + {in2[3],in2};	//手动补充高位的符号位endmodule

而如果将加数都定义成signed类型,则可以直接相加,综合工具会自动在高位扩展符号位来完成计算:

module test 
(input	signed [3 : 0]	in1,in2,output	signed [4 : 0]	out
);assign out = in1 + in2;	//手动补充高位的符号位endmodule

移位操作

不使用signed的情况下,右移首先需要根据最高位的符号来判断这个数是正数还是负数,正数右移需要高位补0,而负数右移则需要高位补1。

比如 -4 右移一位的结果应该是 -2,即4’b1100 >>1 的结果应该是4’b1110,如果高位补0则成了4‘b0110(6),结果就明显错了。所以代码要这么写:

module test 
(input		[3 : 0]	in,output	reg	[3 : 0]	out
);//右移两位
always@(*)
beginout = in >> 2;			//首先右移两位,先默认在高位补0,后面再根据判断来修改if(in[3])				//in是负数out [3:2] = 2'b11;	//高位补的0替换成1
endendmodule

如果将数据定义成了signed类型,则不需要判断正负,可以直接使用 算术右移预算符 >>> 来做移位。算术右移时,高位补充的是符号位。算术右移需要和signed一起使用,因为无符号数的算术右移补充的是0。代码:

module test 
(input	signed [3 : 0]	in,output	signed [3 : 0]	out
);//右移两位
assign out = in >>> 2;	//算术右移高位会自动补符号位endmodule

比较

在不定义signed的情况下,只要比较中出现了负数,那么比较的结果就不能直接对比了,直接对比很容易出错,比如:

`timescale 1ns/1ns
module tb_test();reg	[3:0] a,b;initial begina = 4'd1;	//1b = -4'd3;	//-3if(a > b)$display("a > -3");else$display("a < -3");
end	endmodule

这段打印的结果居然是:

a < -3

也就是说 1居然小于 -3 ?结果明显不对。如果不使用signed来定义变量,那么在判断两个数的大小时,首先需要判断符号位,然后才是判断剩余数的大小。这样写出来的代码非常麻烦。如果把两个数都定义成signed类型,那就可以直接对比了:

module test 
(input	signed [3:0]	in1,in2,output					out
);//当in1大于in2时输出1;其他时候输出0;不考虑二者相等的情况
assign out = (in1 > in2) ? 1'b1 : 1'b0;endmodule

测试结果符合预期:

image-20240403172322160

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/319747.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idm下载速度慢解决办法 idm批量下载怎么用 idm优化下载速度 Internet Download Manager解决下载速度慢的方法教程

IDM (Internet Download Manager)是一款兼容性大&#xff0c;支持多种语言的下载管理软件&#xff0c;它可以自动检测并下载网页上的内容&#xff0c;这正是这一优点&#xff0c;使得它受到了广大用户的喜爱。但是在下载的过程中&#xff0c;我们会遇到idm下载速度慢怎么回事&a…

【设计模式】13、template 模板模式

文章目录 十三、template 模板模式13.1 ppl13.1.1 目录层级13.1.2 ppl_test.go13.1.3 ppl.go13.1.4 llm_ppl.go13.1.5 ocr_ppl.go 十三、template 模板模式 https://refactoringguru.cn/design-patterns/template-method 如果是一套标准流程, 但有多种实现, 可以用 template …

江湖有法受邀参加第四届中国创始人IP生态大会

四月的杭城春意盎然、微风轻拂,到处洋溢着一派欣欣向荣、百花争艳的美好景象。2024 年 4 月 27 日下午 1:30,备受瞩目的第四届中国创始人 IP 生态大会在杭州华礼宴国际礼宴中心盛大开幕。本次大会由“大咖会”主办,以“打造一个圈层,影响一座城”为主题,吸引了众多行业大咖齐聚…

ROS2学习——Docker环境下安装于使用(1)

目录 一、简要 二、ROS2和ROS1区别 三、环境搭建与安装 &#xff08;2&#xff09;拉取ubuntu22.04镜像 &#xff08;2&#xff09;安装ROS2 1. 基本设置 2.设置源 3.安装ROS2功能包 4.测试 四、相关指令学习 1.小海龟测试 2.ros2 node等指令 3.rqt 一、简要 随着R…

API安全

一&#xff0c;什么是API API指的是应用程序编程接口&#xff08;Application Programming Interface&#xff09;&#xff0c;是一组定义了软件组件如何相互交互的规范。通过API&#xff0c;不同的软件可以相互通信和交换数据&#xff0c;实现不同软件之间的集成和互操作。 …

compose调用系统分享功能分享图片文件

compose调用系统分享功能图片文件 简介UI界面提供给外部程序的文件访问权限创建FileProvider设置共享文件夹 通用分享工具虚拟机验证结果参考 本系列用于新人安卓基础入门学习笔记&#xff0c;有任何不同的见解欢迎留言 运行环境 jdk17 andriod 34 compose material3 简介 本案…

线性数据结构-手写队列-哈希(散列)Hash

什么是hash散列&#xff1f; 哈希表的存在是为了解决能通过O(1)时间复杂度直接索引到指定元素。这是什么意思呢&#xff1f;通过我们使用数组存放元素&#xff0c;都是按照顺序存放的&#xff0c;当需要获取某个元素的时候&#xff0c;则需要对数组进行遍历&#xff0c;获取到指…

ton-http-api安装部署

1、拉取github代码 mkdir /data git clone https://github.com/toncenter/ton-http-api.git cd ton-http-api2、创建环境变量 ./configure.py cat .env TON_API_CACHE_ENABLED0 TON_API_CACHE_REDIS_ENDPOINTcache_redis TON_API_CACHE_REDIS_PORT6379 TON_API_CACHE_REDIS_T…

6.k8s中的secrets资源

一、Secret secrets资源&#xff0c;类似于configmap资源&#xff0c;只是secrets资源是用来传递重要的信息的&#xff1b; secret资源就是将value的值使用base64编译后传输&#xff0c;当pod引用secret后&#xff0c;k8s会自动将其base64的编码&#xff0c;反编译回正常的字符…

仿知乎网站问答源码,开源版

仿知乎网站问答源码&#xff0c;开源版 需要一定动手能力 发文章&#xff0c;发视频&#xff0c;发想法&#xff0c;提问回答&#xff0c;注册登录 开发环境 使用技术&#xff1a;springbootthymeleafRedis&#xff1b; 开发环境&#xff1a;tomcat8.0&#xff0c;jdk8.0, ID…

2023下半年软件设计师上午题——冒泡排序

快速排除法&#xff0c;根据冒泡排序特性&#xff0c;每一趟排序都会确实最大/最小值&#xff0c;故升序两趟后&#xff0c;最后两个元素应该是已经排序好的第二大&#xff0c;和最大的元素&#xff0c;所以排除B,D&#xff0c;再因为每次排序都会两两交换&#xff0c;所以排除…

裸金属服务器,云用户的新体验

定义 裸金属服务器&#xff08;Bare Metal Server&#xff09;&#xff0c;是一台既具有传统物理服务器特点的硬件设备&#xff0c;又具备云计算技术的虚拟化服务功能&#xff0c;是硬件和软件优势结合的产物。可以为企业提供专属的云上物理服务器&#xff0c;为核心数据库、关…

【010】基于springboot+vue的校园资产管理

【010】基于springbootvue的校园资产管理 一、系统情况介绍 该系统是基于springbootvue的校园资产管理系统&#xff0c;校园资产管理是一款可以真正提升管理者的办公效率的软件系统。主要有以下功能&#xff1a;个人信息管理、校园资产管理、资产借用管理、入库管理、用户管理…

[Java EE] 多线程(六):线程池与定时器

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

利用大语言模型(KIMI)构建智能产品的信息模型

数字化的核心是数字化建模&#xff0c;为一个事物构建数字模型是一件非常繁杂和耗费人工的事情。利用大语言模型&#xff0c;能够轻松地生成设备的信息模型&#xff0c;我们的初步实验表明&#xff0c;只要提供足够的模板&#xff0c;就能够准确地生成设备的数字化模型。 我们尝…

【CV-CUDA实战】使用Python+TensorRT+CVCUDA优化YOLOv8

目录 什么是CV-CUDA环境准备准备CV-CUDA静态库解压添加至变量将PyBind静态库复制到env下算子设计前处理算子 TensorRT模型加载后处理函数 完整代码输出演示为什么重新写了&#xff1f;结语 什么是CV-CUDA NVIDIA CV-CUDA™ 是一个开源项目&#xff0c;用于构建云规模人工智能 (…

cefsharp实现资源替换如网页背景、移除替换标签、html标识、执行javascript脚本学习笔记(含源码说明)

(一)实现测试(仅供学习参考) 1.1 目标系统页面(登录页)和登录后首页面中2处(一个替换一个移除) 1.2 实现后效果(使用cefsharp自定义浏览器实现以上功能) 1.3 登录后页面替换和移除 系统名称和一个功能菜单li (二)通过分析代码实现脚本编写 2.1 分开处理,设置了…

STM32中断之TIM定时器详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. TIM简述 2. 定时器类型 2.1 基本定时器 2.2 通用定时器 2.3 高级定时器 3. 定时中断 4. 代码示例1 5. 代码示例2 1. TIM简述 定时器的基本功能&#xff1a;定时器可以在预定的时间间隔内产生周…

网络安全之弱口令与命令爆破(中篇)(技术进阶)

目录 一&#xff0c;什么是弱口令&#xff1f; 二&#xff0c;为什么会产生弱口令呢&#xff1f; 三&#xff0c;字典的生成 四&#xff0c;使用Burpsuite工具验证码爆破 总结 笔记改错 一&#xff0c;什么是弱口令&#xff1f; 弱口令就是容易被人们所能猜到的密码呗&a…

基于LLama3、Langchain,Chroma 构建RAG

概要&#xff1a; 使用Llama3 Langchain和ChromaDB创建一个检索增强生成&#xff08;RAG&#xff09;系统。这将允许我们询问有关我们的文档&#xff08;未包含在训练数据中&#xff09;的问题&#xff0c;而无需对大型语言模型&#xff08;LLM&#xff09;进行微调。在使用RA…