如何检测verilog中的溢出?

发布于 2025-01-12 00:45:54 字数 322 浏览 0 评论 0原文

所以我的目标是在添加两个 64 位变量 A 和 B 时检测溢出。我尝试了一些方法但没有成功。起初我做了:

          if ((A[63])== B[63]==1)
            Overflow=1; 

那不起作用,所以我做了:

if(A != (ALU_Result-B))
Overflow=1;

ALU_Result 是我的结果顺便说一句。我认为它保存的值将是第一个 64 位,因此这个方程将给出标志,但这也不起作用。如何创建旗帜?另外,如果发生溢出,那么进位是否自动为1?

So my goal is to detect overflow when adding two 64-bit variables A and B. I tried a couple things that didn't work out. At first I did:

          if ((A[63])== B[63]==1)
            Overflow=1; 

That didn't work so I did:

if(A != (ALU_Result-B))
Overflow=1;

ALU_Result is my result btw. I thought that the value it held will be the first 64 bit so this equation would give the flag but this didn't work either. How do I create the flag? Also, if there is overflow, then is the carry automatically a 1?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

荒岛晴空 2025-01-19 00:45:54

对于无符号数,当总和小于任一操作数时,就会发生溢出。

对于有符号(二进制补码)数,当两个操作数均为负但总和为正时,或者两个操作数均为正且总和为负时,就会发生溢出。

此 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

For unsigned numbers, overflow occurs when the sum is less than either of the operands.

For signed (two's complement) numbers, overflow occurs when both operands are negative, but the sum is positive, or if both operands are positive and the sum is negative.

This Verilog example uses 8 bit numbers for the unsigned case and 32 bit numbers for the signed case. It does not matter what size the numbers are.
Check for overflow using sign of the operands and result as detailed above, and illustrated in the code below.

Verilog ex in a testbench process of adding unsigned, unsigned numbers and detecting overflow:

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

Testbench run results here:

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
余罪 2025-01-19 00:45:54

最直接的方法是使用一个临时变量,该变量有一个额外的位,这样总和就不会溢出。我已经展示了如何处理无符号数字。通过检查正溢出和负溢出,可以很容易地将其扩展到有符号数。综合工具应该足够智能,可以简化此逻辑,而无需进行任何位操作。

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

The most direct way to do this is to have a temporary variable which has an extra bit so the sum does not overflow. I have shown how to handle this for unsigned numbers. It is easy enough to expand this to signed numbers by checking for both positive and negative overflow. Synthesis tools should be smart enough to simplify this logic without you doing any bit manipulation

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

Another way to do it for unsigned numbers is to directly use that extra bit as the overflow flag. This options doesn't clip your result, but I am not sure you care about that:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文