如何检测verilog中的溢出?

问题描述 投票:0回答:2

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

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

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

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

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

verilog
2个回答
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

0
投票

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

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
© www.soinside.com 2019 - 2024. All rights reserved.