
本文共 6023 字,大约阅读时间需要 20 分钟。
有符号数的计算在 Verilog 中是一个很重要的问题(也很容易会被忽视),在使用 时,需要涉及到有符号数的加法和乘法,在之前的程序中我把所有的输入输出和中间信号都定义成有符号数,这样在计算时没有出现问题(实际在之前的程序中遇到了有符号和无符号数的问题,最后滤波结果不对,博客的程序是已经改正过的),下面实际试验一下 Verilog 的乘法问题;
1. 编写程序测试无符号数和有符号数的乘法
编写程序如下,其中,乘法的两个乘数分别是无符号、有符号的四种组合,输出的积也是分为无符号和有符号,共计 8 种可能;
module signed_test( input [7:0] data_in_unsigned_1, input [7:0] data_in_unsigned_2, input signed [7:0] data_in_signed_1, input signed [7:0] data_in_signed_2, output [15:0] data_out_000, output [15:0] data_out_001, output [15:0] data_out_010, output [15:0] data_out_011, output signed [15:0] data_out_100, output signed [15:0] data_out_101, output signed [15:0] data_out_110, output signed [15:0] data_out_111);//无符号 = 无符号 * 无符号 assign data_out_000 = data_in_unsigned_1 * data_in_unsigned_2;//无符号 = 无符号 * 有符号 assign data_out_001 = data_in_unsigned_1 * data_in_signed_2;//无符号 = 有符号 * 无符号 assign data_out_010 = data_in_signed_1 * data_in_unsigned_2;//无符号 = 有符号 * 有符号 assign data_out_011 = data_in_signed_1 * data_in_signed_2; //有符号 = 无符号 * 无符号 assign data_out_100 = data_in_unsigned_1 * data_in_unsigned_2;//有符号 = 无符号 * 有符号 assign data_out_101 = data_in_unsigned_1 * data_in_signed_2;//有符号 = 有符号 * 无符号 assign data_out_110 = data_in_signed_1 * data_in_unsigned_2;//有符号 = 有符号 * 有符号 assign data_out_111 = data_in_signed_1 * data_in_signed_2; endmodule
生成的 RTL 图如下:

如果把 16 位的二进制 16’b1100_0000_0000_0011 当成是一个有符号数来看,那么最高位是符号位,且剩下的数据时原来的数据二进制表示后取反再加1(补码表示),要计算它对应的十进制数
(1)先去掉符号位,保留剩下的 15-bit 的 100_0000_0000_0011; (2)把 100_0000_0000_0011 取反,得到 011_1111_1111_1100; (3)把 011_1111_1111_1100 的最低位 + 1,得到 011_1111_1111_1101; (4)011_1111_1111_1101 按照无符号数换算成十进制是 16381; (5)把最高位符号位加上,0代表正数,1代表负数,所以最后换算是 -16831;Windows 计算器默认最高位是符号位;
测试数据如下:

initial begin data_in_unsigned_1 = 8'hff; //255 data_in_unsigned_2 = 8'hf0; //240 data_in_signed_1 = 8'hff; //-1 data_in_signed_2 = 8'hf0; //-16 #200; data_in_unsigned_1 = 8'hff; //255 data_in_unsigned_2 = 8'h0f; //15 data_in_signed_1 = 8'hff; //-1 data_in_signed_2 = 8'h0f; //15 #200; data_in_unsigned_1 = 8'd127; //127 data_in_unsigned_2 = 8'd15; //15 data_in_signed_1 = -8'sd127; //-127,十进制有符号数赋值,必须要用 sd 表示 data_in_signed_2 = -8'sd15; //-15 #200; data_in_unsigned_1 = 8'd128; //128 data_in_unsigned_2 = 8'd15; //15 data_in_signed_1 = -8'sd128; //-128 data_in_signed_2 = -8'sd15; //-15 #200; data_in_unsigned_1 = 8'd127; //127 data_in_unsigned_2 = 8'd15; //15 data_in_signed_1 = -8'sd127; //-127 data_in_signed_2 = 8'sd15; //15 #200; data_in_unsigned_1 = 8'd128; //128 data_in_unsigned_2 = 8'd15; //15 data_in_signed_1 = -8'sd128; //-128 data_in_signed_2 = 8'sd15; //15 #200; data_in_unsigned_1 = 8'd127; //127 data_in_unsigned_2 = 8'd15; //15 data_in_signed_1 = 8'sd127; //127 data_in_signed_2 = -8'sd15; //-15 #200; data_in_unsigned_1 = 8'd127; //127 data_in_unsigned_2 = 8'd15; //15 data_in_signed_1 = 8'sd127; //127 data_in_signed_2 = 8'sd15; //15 #200; $stop;end
2. 仿真分析
计算的结果仿真如下:



3. 有符号数乘法的另一种计算
前面说的计算时将涉及到的相关量全部定义为有符号数是一种计算方法,此外,通常情况下可能会定义的无符号数,但是实际传入的是有符号数,比如下面的输入和输出都没有指定成 signed 有符号数,计算时默认是按照无符号数计算(实际上我感觉是把读取到的 8 位二进制数当做原码去算),此时若外部传入的数据实际上是有符号数(比如 FIR 滤波器传入了正负均有的待滤波信号),那么需要对符号位进行扩展来计算乘法和加法;
module signed_test_2(
input [7:0] data_in_1, input [7:0] data_in_2, output [15:0] data_out_1, output [15:0] data_out_2 ); 对于乘法,需要扩展符号位 到 和积的位数相等,比如乘数a为 N-bit,乘数 b 为M-bit,两个相乘得到 N+M 位数据,此时需要对 a 扩展 M-bit 到 N+M 位,对 b 扩展 N-bit 到 N+M 位; 下面,使用 位拼接符 { } 来做演示,位拼接符可以按照二进制的位来进行高低位的拼接,假设 data_in_1= 8’b1000_0011,对于 { {8{data_in_1[7]}},data_in_1} 可以这样理解: (1)先看 8{data_in_1[7]},表示取出 8-bit 数据 data_in_1 的最高位 data_in_1[7],重复 8 次,相当于 { data_in_1[7], data_in_1[7], data_in_1[7], data_in_1[7], data_in_1[7], data_in_1[7], data_in_1[7], data_in_1[7] }, 即高位扩展 8-bit 的 1; (2){ {8{data_in_1[7]}},data_in_1} 相当于在 data_in_1 的前面补上 8 个 data_in_1[7],即 结果为 16-bit 的 16’b1111_1111_1000_0011;//不做符号位扩展,直接相乘assign data_out_1 = data_in_1 * data_in_2;//做符号位扩展,再相乘assign data_out_2 = { { 8{ data_in_1[7]}},data_in_1} * { { 8{ data_in_2[7]}},data_in_2};
仿真测试数据如下,1 处用十六进制给出数据,2 处用有符号的十进制赋值,3 处是为了和 2 处对比,看最后赋值是否一样(看到有博客说 3 的赋值是错的,所以测试一下);



除此之外,还可以调用乘法器的 IP 来代替 乘法符号 *,或者加法器的 IP 来代替 加法符号 +,在 IP 核中配置输入输出为有符号数即可。
发表评论
最新留言
关于作者
