Verilog基础:位宽拓展和有符号数运算的联系

相关文章

Verilog基础:表达式位宽的确定(位宽拓展)

Verilog基础:表达式符号的确定

Verilog基础:数据类型

Verilog基础:case、casex、casez语句

Verilog基础:casex和full_case、parallel_case的使用

Verilog基础:task和function的使用(一)

Verilog基础:task和function的使用(二)

Verilog基础:表达式中的整数常量(integer)


我们以Verilog官方手册中的例子来看当有符号数遇到符号拓展时会发生什么,见下图。

Verilog基础:位宽拓展和有符号数运算的联系_第1张图片

在阅读以下内容前,需要知道,对于有符号数和无符号数,数字本身是不会改变的,改变的只是对这串数字的解释,有符号数将最高位当做符号位,剩下的位当做是补码,无符号数则没有符号位。没有位宽和基数的常数被当做32位有符号数,算术运算符只有在操作数都为有符号数时,才会执行有符号数计算,结果才是有符号数。例:3、2、1均被当做有符号数,3/-1是有符号数除法,结果为-3的补码,2'd3/-1是无符号数除法,结果为0。

我们定义了一个32位的有符号整数变量(variable),一个16位的无符号(默认)寄存器变量,一个16位的有符号(signed)寄存器变量。

intA=-4'd12;首先我们发现赋值表达式左端的intA是32位的,根据上下文位宽拓展规则,右端的4位常数会被首先拓展至32位,注意:此时右端的数是一个无符号数(因为在d前没有s符号),所以会被高位补0拓展为000...01100,但由于常数前又有取负运算符,所以最后表达式的结果为111...10100(符号位取反,其他位取反加一),即-12的32位补码,但此时的表达式结果并不被当做有符号数-12来看,而是解释为一个无符号的大正数,这同样是因为d前没有s符号。最后将表达式的值赋值给有符号整数变量intA,所以这个原来的大整数又被解释为有符号数,最后intA的值还是-12。

regA=intA/3;赋值表达式右端的结果根据有符号数除法的规则,得到的结果是-4的32位补码,111...11100,且解释为有符号数,即但之后将表达式的值赋值给了16位无符号寄存器变量,根据截断法则,高16位被直接截断(包括符号位),低16位被赋值给regA且被解释为无符号数,即regA得到的是1111111111111100,即65532。

regA=-4'd12;intA=-4'd12;同理,赋值表达式右端的无符号4位常数被补0拓展到regA的宽度,即16位的0000000000001100,又因为常数前有取负运算符,所以最后右端表达式的结果为1111111111110100,即-12的16位补码,但此时的右端表达式结果并不被当做有符号数-12来看,而是解释为一个无符号的大正数,这是因为d前没有s符号。最后将右端表达式的值赋值给无符号寄存器变量regA被解释为无符号数,即regA得到的是1111111111110100,即65524。

intA=regA/3;赋值表达式右端的结果根据无符号数除法的规则,得到的结果是无符号数21841(32位,因为赋值表达式左侧的intA和常数3都是32位),然后将右侧表达式的值赋值给32位有符号整数变量intA,但由于此时32位无符号数21841的最高位为0被解释为正数,所以最后intA得到的结果还是21841。

intA=-4'd12/3;赋值表达式左端的intA和右端常数3均为32位,所以无符号常数4'd12首先被补0拓展至32位,000...01100,然后首先执行取负运算符,运算结果为32位无符号数111...10100,4294967284,即然后运算无符号数除法/3,得到右端表达式结果为32位无符号数1431655761。然后将右侧表达式的值赋值给32位有符号整数变量intA,但由于此时32位无符号数1431655761的最高位为0被解释为正数,所以最后intA得到的结果还是1431655761。

regA=-12/3;此时右端两个常数均被当做32位有符号数,然后执行有符号数除法,最后得到的结果为有符号数-4的32位补码,111...11100,然后将值赋给16位无符号寄存器变量regA,高16位被直接截断(包括符号位),低16位被赋值给regA且被解释为无符号数,即regA得到的1111111111111100,即65532。

regS=-12/3;右端运算同上所述,最后将值赋给16位无符号寄存器变量regS,高16位被直接截断(包括符号位),低16位被赋值给有符号寄存器变量regS且被解释为有符号数,即regS得到的1111111111111100,即-4。

regS=-4'sd12/3;赋值表达式右侧的3位32位有符号数,所以有符号数12被符号拓展为32位有符号数111...11100,然后执行取负运算符,运算结果为有符号数4的32位补码,000...00100,然后执行有符号数除法,结果为32位有符号数1,将其赋值给有符号寄存器变量regS,regS的值仍然是1。

以上的关键在于,符号拓展是在所有运算开始前就确定的,否则你会疑惑为什么-4'sd12是先被符号拓展至32位111...11100,再被取负为000...00100,而不是先取负为0100,再符号拓展至32位000...00100。

关于位宽问题更深入的讨论,可以看这篇文章。

https://blog.csdn.net/weixin_45791458/article/details/128772558?spm=1001.2014.3001.5501

你可能感兴趣的:(Verilog,fpga开发,硬件工程,前端)