完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
在写代码时,需要注意信号的位宽,最终的结果取决于“*”号左边信号的位宽,保存低位,丢弃高位。
“2’ b11 * 3’b101”得到的二进制值是“4’b1111”,但保存结果取决 于“*”号左边信号的位宽。C的位宽是 1,保存最低1位,所以c的值为1’b1。由于d的位宽有2位,结果保存低2位,所以d的值为2’b11。由于e的位宽有3位,结果保存低3位,所以e的值为3’b111。f的位宽有 4位,所以运算的结果可以保存低4位,所以f的值为 4’b1111。注意的是f,该信号有5位,4’b1111赋给5位信号,结果是高位补0,所以其结果为5’b01111。 3.4.1.4 除法运算符和求余运算符 除法运算符,可以在Verilog 代码中直接使用符号“/”,而求余运算符是“% ”
除法的电路示意图: 图 16 求余的电路示意图 图 17 综合器可以识别除法运算符和求余运算符,但是这两种运算符包括大量的乘法、加法和减法操作,所以在FPGA里, 除法器的电路是非常大的,综合器可能无法直接转成上面电路。 为什么除法和求余会占用大量的资源,我们分析下十进制除法和求余的过程,例如122除以11。 图 18 我们做上面运算的过程中,涉及到多次的移位、乘法、减法等运算。也就是一个除法,包括了多个乘法器、减法器等,需要比较大的硬件资源。二进制也是同样的道理。 所以,在设计代码中,我们一般不使用除法和求余。在算法中,想各种办法来避免除法和求余操作 。在数字信号处理、通信、图像处理中,你会看到大量的乘法、加减法等,却很少看到除法和求余。 但在仿真测试中,是可以使用除法和求余的,其只是仿真测试用途,不用综合成电路,自然也就不关心占用多少资源了。 3.4.1.5 补码的由来 FPGA 实现各种算法的时候,首要的就是保证运算结果的正确性,否则一切无所谈成。我们在分析加加法运算符和 减法运算符的时候,发现保存结果的信号位宽,对正确性有很大的影响。 例如下面的加法运算
从上表我们可以发现,如果不保存进位的话,当加法出现进位的时候,计算的结果是不正确的,只有保存了进位,计算的结果才是正确的。 结论:使用加法的时候,为了保证结果的正确性,必须保存进位,也就是结果要扩展位宽。 例如两个8位的数相加,则结果要扩展一位,保存为9位。
我们再来分析一下减法,如下表所示例子。
注意表中和2’b00- 2’b01,结果是2’b11,对应的十进制值为3,但我们期望的结果是“-1”。同样的道理, 2’b01 - 2’b11,结果是2’b10,对应的十进制值为2,而我们期望的结果是“-2”。所以上面的结果是不正确的。 我们期望结果是有正负的,那我们可增加一个符号位,业内比较约定的,就是最高位为0时表示正数,最高位值为1表示负数。然后我们用低2位表示数据值,结果如下表
增加符号位后,我们还是发现与预期不符号。例如表中的 2’b00- 2’b01,结果是3’b111,对应的十进制值为- 3,但我们期望的结果是“-1”。所以上面的结果仍然是不正确的。 现在我们重新对二进制数“000~111 ”进行如下转换: a. 正数:保持不变 b. 负数:符号位保持不变,数值取反加 1。 也就是说,如果是正数“ +1”,之前是用“001”表示,现在仍然是用“001”表示。如果是负数“-1”,之前是用“101”表示,现在则是用“111”表示。负数“-3”,之前是用“111”表示,现在则是用“101”表示。 这种表示方式就是补码表示方式。 改为用补码来表示后,再来分析下结果。
上面的结果全部正确的,与预期一致的。完全没有对代码做任何变化,只是改了一下数据的定义,就能实现正确的结果。 之前的讨论,加数、被加数、减数和被减数,都没有使用有符号数。现在我们用有符号数的补码表示一下。现在假设加数、被加数、减数和被减数都是2位(范围为 - 2~1),考虑到进位和借位原因,结果用3位来保存(范围为-4~3)。列出下表。
有些可见,定义为补码之后,我们只要考虑好保存结果的位宽,就可以将数据直接进行加、减法运算,自然就能得 到正确的结果。事实上,在FPGA甚至计算机系统中,所有数据的保存的方式都是补码的形式。 更多关于补码的内容,读者可以参阅相关资料。 3.3.2 关系运算符 关系运算符有:? > (大于)、?<(小于)、 ? >=(不小于)、? <=(不大于)、==(逻辑相等)和!= (逻辑不等)。 关系操作符的结果为真(1)或假(0)。如果操作数中有一位为X或Z,那么结果为X 。 例:
如果操作数长度不同,长度较短的操作数在最重要的位方向(左方)添0补齐。例如:
在逻辑相等与不等的比较中,只要一个操作数含有x或z,比较结果为未知(x),如:
比较结果不定,也就是说值为x 。 3.4.3 逻辑运算符 在Verilog HDL语言中存在3种逻辑运算符,它们分别是: (1)&&:逻辑与; 3.4.3.1 逻辑与(&&) “&&”是双目运算符,要求有两个操作数,如a && b。 (1)1位逻辑与:
A和B都为1时,C为1;否则C为0。 对应硬件电路图: 图 19 (2)多位逻辑与:
A或B都不为0时,C为1,否则为0。 对应硬件电路图: 图 20 3.4.3.2 逻辑或(||) “|| ”是双目运算符,要求有两个操作数,如 a | | b 。 (1)1位逻辑或
A和B其中1个为1,C为1;否则C为0。 对应硬件电路图: 图 21 (2)多位逻辑或
A和B其中1个非0,C为 1;否则C为0。 对应硬件电路图: 图 22 3.4.3.3 逻辑非(!) “!”是单目运算符,只要求有一个操作数,如!(a>b)。
操作数a,先判断非a是否为真,为真就执行{}内的操作,为假的话就结束操作。 表**为逻辑运算的真值表,它表示当a和b的值为不同的组合时,各种逻辑运算所得到的值。 表**逻辑运算的真值表
逻辑运算符最后的结果只有逻辑真或逻辑假两种,即1或0。我们一般用逻辑运算符作判断条件,逻辑与操作只能是两个1位宽的数,只有两个表达式同时为真才为真,有一个为假则为假。 逻辑运算符的结果只有逻辑真或者逻辑假。 如果操作数是多位的,则将操作数看做整体,若操作数中每一位都是0值;则为逻辑0值;若操作数中有1,则做位逻辑1值。
由于4’b0111和4’b1000都不是0,不为0则认为是逻辑真,所以上面的代码,等效于下面代码 。
也就是结果为a为逻辑真,b为逻辑真,c为逻辑假。 3.4.3.4 逻辑运算符的优先级 逻辑运算符中“&&”和 “||” 的优先级低于算数运算符;“! ”的优先级高于双目逻辑运算符。 举例如下:
请读者注意上面的代码,a和b都是多比特信号,两个多比特信号进行逻辑与。 该句代码的正确理解是:当a不等于0并且b不等于0时,d的值为1。 但是从直观上看,很多工作多年的工程师,也不能直接知道上面所隐含的意思。有多少人知道,不等于0就是表示逻辑真,等于0就表示逻辑假呢? 写出上面的代码,虽然没错,但纯粹是炫耀自己的技术,这是毫无意义的。 还有一点,很容易出现误设计的情况,本来是要表达assign d =a & b的。 写出直观能理解,让人(包括自己)一眼就能懂的代码 ,非常重要。所以我们建议上面代码写成如下形式。
明德扬使用心得2:不要试图记住优先级,而是要多用括号。 实际上,工程师们也没有多少人能记得优先级,即使知道优先级是什么,工作效率也不见得提高多少。例如:
假如我们没记住运算符的优先级,遇到类似这三个例子的情况时,势必会花一定的时间来理清思路,思考究竟先判断哪部分;假如有工程师能记住优先级,他们之间也需要就这些代码进行沟通和检查。此外,人是容易犯错的,而且这些错误很难被检查出来。 因此,为了提高程序的可读性,明确表达各运算符间的优先关系,我们建议多使用括号。上的三个例子就可分别写成:
明德扬使用心得3:多用“逻辑与”和“逻辑 或”,少用逻辑非 “逻辑与”翻译成中文就是“并且”,“逻辑或”翻译成中文就是“或者”。 假设有一个信号flag,0表示空闲,1表示忙。 “ (!(flag==0) && a==4’b1000) ”,读起来就是“在空闲的时候取其反状态,并且当a等于4’b1000时”。这样读起来是不是非常拗口,并且在看这代码时,还不得不多想一层,脑袋还要多转一下弯? 因此上面的例子,我们建议写成“ flag==1 && a==4 ’b1000”,读起来就是“在忙并且 a等于4’b1000的时候”。 3.3.4 按位逻辑运算符
这些操作符在输入操作数的对应位上按位操作,并产生向量结果。下表显示对于不同按位逻辑运算符按位操作的结果: 图 23 3.4.4.1 单目按位与 & 目运算符&,后面跟着的是信号,表示的是这个信号的每位之间相与。例如
上面代码等价于 C = A[3] & A[2] & A[1] & A[0]; 如果A=4’b0110, C的结果为0。 3.4.4.2 单目按位或 | 单目运算符|,后面跟着的是信号,表示的是这个信号的每位之间相或。例如
上面代码等价于 C = A[3] | A[2] | A[1] | A[0] ; 如果A=4’b0110, C的结果为1。 3.4.4.3 单目按位非 ~ 单目运算符~,后面跟着的是信号,表示的是这个信号的每位取反。例如
上面代码等价于 C[3] = ~A[3], C[2] = ~A[2],C[1] = ~A[1],C[0] = ~A[0]。 如果A=4’b0110,C的结果 为4’b1001。 3.4.4.4 双目按位与 & 双目运算符&,左边和右边都是信号,表示的是这两个信号之间,对应的位相与。例如
上面的代码等价于:C[0] = A[0] & B[0], C[1] = A[1] & B [1] ,C [2] = A[2] & B[2] ,C[3] = A[3] & B[3] 。如果 A=4’b0110,B=4’b1010, C的结果为4’b0010。 如果操作数长度不相等, 长度较小的操作数在最左侧添0补位。例如:
上面的代码等价于:C[0] = A[0] & B[0], C[1] = A[1] & B [1] ,C [2] = 0] & B[2],C[3] = 0 & 0。 3.4.4.5 双目按位或 | 双目运算符|,左边和右边都是信号,表示的是这两个信号之间,对应的位相或。例如:
上面的代码等价于:C[0] = A[0] | B[0], C[1] = A[1] | B[1] ,C[2] = A[2] | B[2] , C[3] = A[3] | B[3]。如果A=4’b0110,B=4’b1010,C的结果为4’b1110。 如果操作数长度不相等, 长度较小的操作数在最左侧添0补位。例如,
上面的代码等价于:C[0] = A[0] | B[0], C[1] = A[1] | B[1] ,C[2] = 0] | B[2],C[3] = 0 | 0。 |
|||||
|
|
|||||
792 浏览 0 评论
NVMe over Fabrics 国产 IP:高性能网络存储解决方案
750 浏览 0 评论
130 浏览 0 评论
NVMe高速传输之摆脱XDMA设计54:如何测试队列管理功能2
437 浏览 0 评论
NVMe高速传输之摆脱XDMA设计53:如何测试队列管理功能
769 浏览 0 评论
4574 浏览 64 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-15 03:47 , Processed in 0.786246 second(s), Total 61, Slave 44 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖