这是我写的简单代码。从'outt'得到122116.但如果我将'outt'宽度改为33位([32:0])那么代码似乎工作并给出正确答案-140028 。这种行为的原因是什么?
`timescale 1ns / 1ps
module valu_parser(clk,outt);
input clk;
reg signed [31:0] r_1;
reg signed [31:0] r_2;
output reg signed [31:0] outt;
initial begin
r_1 = -47938;
r_2 = -150096;
end
always @ (posedge clk) begin
outt <= ((r_1 + r_2)* 11585 + 8192)>>>14;
end
endmodule
答案 0 :(得分:1)
您正在执行至少需要33位的操作(右移之前的临时结果使用33位),理论上它可能需要32+“被乘数常量的大小”,假设r_1和r_2不是常数。
如果您考虑代码将生成的硬件,则需要将这些位临时存储在某个位置以允许硬件首先执行乘法,然后添加后跟右移。
这将解决问题,但也会产生比最初想要的更多的寄存器。如果您使用此模块生成常量,我建议对常量进行硬编码。
module valu_parser(clk,outt);
input clk;
reg signed [31:0] r_1;
reg signed [31:0] r_2;
reg signed [32:0] temp;
output reg signed [31:0] outt;
initial begin
r_1 = -47938;
r_2 = -150096;
end
always @ (posedge clk) begin
temp <= ((r_1 + r_2)* 11585 + 8192);
end
assign outt = temp>>>14;
endmodule
这个概念可以在这里看到:https://www.edaplayground.com/x/3BXy。
答案 1 :(得分:1)
在表达式中,Verilog需要决定在计算中使用多少位。
+
和*
运算符会生成所谓的上下文确定的表达式。使用表达式F = A + B;
,使用的位数是F
,A
和B
的最大值。这通常可以正常使用,因为通常您会确保F
足够宽,以存储添加A
和B
的结果。同样,表达式F = A * B;
通常可以正常工作,因为通常您会确保F
足够宽,以存储乘以A
和B
的结果。
但是,通过添加右移运算符,您可以使变量的分配比计算移位运算符左侧表达式实际需要的位数更窄。 Verilog在计算中使用的位数是outt
,r_1
,r_2
,11585
和8192
宽度的最大值。所有这些都是32位宽(包括11585
和8192
),因此在计算中使用32位。正如您所发现的,32位是不够的,但是,根据您选择的值,33位是。对于其他值,33位也不够。对于一个完全灵活的解决方案,您应该使用66位(32 + 32 + 1 + 1) - 32位+ 32位进行乘法,再加1位进行每次加法。
问题的解决方案是让r_1
和/或r_2
更宽或使用中间值(如此处Hida的答案所示)。
答案 2 :(得分:-1)
当您在11585上乘以-198034(r1 + r1)时,您的结果最高位为0(outt [31]),那么如果您有32位有符号值,则其开始为正,并且在答案中您有正结果。当你将它改为33bit时,你的最高位是1(outt [32]),结果是负值,你有正确答案。