所以我的目标是在添加两个 64 位变量 A 和 B 时检测溢出。我尝试了一些方法,但没有成功。一开始我是这样的:
if ((A[63])== B[63]==1)
Overflow=1;
那不起作用,所以我这样做了:
if(A != (ALU_Result-B))
Overflow=1;
ALU_Result 是我的结果。我认为它保存的值将是第一个 64 位,因此这个方程将给出标志,但这也不起作用。如何创建旗帜?另外,如果发生溢出,进位是否自动为1?
对于无符号数,当总和小于操作数中的任意一个时,就会发生溢出。
对于有符号(二进制补码)数字,当两个操作数均为负但总和为正时,或者两个操作数均为正且总和为负时,就会发生溢出。
此 Verilog 示例对无符号情况使用 8 位数字,对有符号情况使用 32 位数字。数字的大小并不重要。 使用操作数的符号和结果检查溢出,如上面详述,并在下面的代码中说明。
Verilog ex 在添加无符号、无符号数字和检测溢出的测试平台过程中:
module tb();
reg [7:0] a_unsigned;
reg [7:0] b_unsigned;
reg [7:0] unsigned_sum;
integer a_signed;
integer b_signed;
integer signed_sum;
bit overflow;
// --------------------------------------------------------------------------
// Print signed
// --------------------------------------------------------------------------
task printSigned(int Ain, Bin,SumIn ,logic overflow);
$display("---- Printing Signed Check ----");
$display("Ain = %0d, Bin = %0d, SumIn = %0d, overflow = %0d\n",
Ain,Bin,SumIn,overflow);
endtask
// --------------------------------------------------------------------------
// Print unsigned
// --------------------------------------------------------------------------
task printUnsigned(logic [7 : 0] a_in, b_in, sum_in ,logic overflow);
$display("---- Printing Unsigned Check ----");
$display("a_in = %0d, b_in = %0d, sum_in = %0d, overflow = %0d\n",
a_in,b_in,sum_in,overflow);
endtask
// --------------------------------------------------------------------------
// check_signed_overflow
// --------------------------------------------------------------------------
function automatic logic checkSignedOverflow (input int a_in, b_in, sum_in) ;
reg overflow;
if((a_in > 0 && b_in > 0 && sum_in < 0)
||
(a_in < 0 && b_in < 0 && sum_in > 0))
overflow = 1'b1;
else
overflow = 1'b0;
return overflow;
endfunction
// ----------------------------------------------------------------------------
// check_unsigned_overflow
// ----------------------------------------------------------------------------
function automatic logic checkUnsignedOverflow (input reg [7:0] Ain,Bin,SumIn);
reg overflow;
if(SumIn < Ain || SumIn < Bin)
overflow = 1'b1;
else
overflow = 1'b0;
return overflow;
endfunction
initial
begin
// ----------------------------------------------------------------
// signed overflow , add two positives get a negative
// ----------------------------------------------------------------
a_signed = 32'h7fffffff;
b_signed = 32'h7fffffff;
//
signed_sum = a_signed + b_signed;
overflow = checkSignedOverflow(a_signed,a_signed,signed_sum);
printSigned(a_signed,a_signed,signed_sum,overflow);
#1;
// ----------------------------------------------------------------
// signed no overflow
// ----------------------------------------------------------------
a_signed = 32'hf;
b_signed = 32'hf;
//
signed_sum = a_signed + b_signed;
overflow = checkSignedOverflow(a_signed,a_signed,signed_sum);
printSigned(a_signed,a_signed,signed_sum,overflow);
#1;
// ----------------------------------------------------------------
// unsigned no overflow
// ----------------------------------------------------------------
a_unsigned = 25;
b_unsigned = 25;
//
unsigned_sum = a_unsigned + b_unsigned;
overflow = checkUnsignedOverflow(a_unsigned,b_unsigned,unsigned_sum);
printUnsigned(a_unsigned,b_unsigned,unsigned_sum,overflow);
#1;
// ----------------------------------------------------------------
// unsigned overflow
// ----------------------------------------------------------------
a_unsigned = 255;
b_unsigned = 255;
//
unsigned_sum = a_unsigned + b_unsigned;
overflow = checkUnsignedOverflow(a_unsigned,b_unsigned,unsigned_sum);
printUnsigned(a_unsigned,b_unsigned,unsigned_sum,overflow);
#1;
$finish;
end
endmodule
测试台运行结果在这里:
xcelium> run
a_in = 2147483647, b_in = 2147483647, sum_in = -2, overflow = 1
a_in = 15, b_in = 15, sum_in = 30, overflow = 0
a_in = 25, b_in = 25, sum_in = 50, overflow = 0
a_in = 255, b_in = 255, sum_in = 254, overflow = 1
最直接的方法是使用一个临时变量,该变量有一个额外的位,这样总和就不会溢出。我已经展示了如何处理无符号数字。通过检查正溢出和负溢出,可以很容易地将其扩展到有符号数。综合工具应该足够智能,可以简化此逻辑,而无需进行任何位操作
logic [63:0] A;
logic [63:0] B;
logic [64:0] A_plus_B;
logic [63:0] A_plus_B_clipped;
logic overflow;
always_comb begin
A_plus_B = A + B;
if(A_plus_B > 65'h0_FFFF_FFFF_FFFF_FFFF) begin
// Overflow happened, set the flag and clip
// the output
overflow = 1'b1;
A_plus_B_clipped = 64'hFFFF_FFFF_FFFF_FFFF;
end
else begin
// No overflow so we can cast the result to
// a 64-bit number
overflow = 1'b0;
A_plus_B_clipped = 64'(A_plus_B);
end
end
对于无符号数,另一种方法是直接使用该额外位作为溢出标志。此选项不会剪切您的结果,但我不确定您是否关心这一点:
logic [63:0] A;
logic [63:0] B;
logic [63:0] A_plus_B;
logic overflow;
always_comb begin
{overflow, A_plus_B} = A + B;
end