AAA
AAA

Reputation: 191

Writing a Verilog function to Locate the index of the first one on the right in the vector

I am Writing a Verilog function to Locate the index of the first one on the right in the vector.If the vector has no ones, the function should returns the value to the vector’s highest index + 1. Here is the code :

module m ();
 parameter n = 3;
  function integer Locate_one (input [n-1:0] a );
    Locate_one ='dx;
    for (integer i =n-1 ; i<=0 ; i=i-1)
      begin
        if(a[i] == 1'b1)
          begin
          Locate_one=i;
            break; 
          end
    end
  
    if (Locate_one=='dx)
      Locate_one=n;
  
  
  
  endfunction
initial begin 
  reg [n-1:0] a = 3'b111;
integer result =  Locate_one (a);
  
  $display("output is %d ", result);
end 
endmodule

Th questions are as follows :

  1. How to break out of the function when we find the highest one ? I have used the keyword break, which is as I found online, is a valid SystemVerilog keyword not Verilog Keyword.
  2. The strategy that I have used to know that there is no one in the vector is that I have initialized the return integer to X and then I have compared the variable to X at the end of the function. Is this a good way to do so or there is another better way to do this comparison ?

Upvotes: 0

Views: 6312

Answers (2)

dave_59
dave_59

Reputation: 42623

There are a number of problems with your code.

  1. You cannot use the == to compare with x—it always returns false. you must use the === operator
  2. You are initializing two static variables a and result and the order of initializations is not defined. They are not procedural statements. SystemVerilog has made implicitly static variable initializations inside procedural code illegal, and that is the only backward incompatibility with Verilog I can think of.
  3. Your code has a lot of SystemVerilog constructs besides break
    1. declaring a variable in a for loop
    2. a function/task body without begin/end keywords.
  4. You should not be using x values in your code. It's not synthesizable, and it makes debugging your code more difficult if you made a mistake.
  5. Your loop condition was the opposite of what you needed.

You can use a disable statement to get functionality similar to a break if you want strict Verilog compatibility.

module m ();
 parameter n = 5;
  function integer Locate_one (input [n-1:0] a );
    integer i;
    begin : block
    Locate_one = n;
      for (i =n-1 ; i>=0 ; i=i-1)
      begin
        if(a[i] == 1'b1)
          begin
          Locate_one=i;
            disable block; 
          end
    end
    end 
  endfunction
  
    reg [n-1:0] a = 3'b111;
initial begin 
integer result;  
  result =  Locate_one (a);     
  $display("output is %d ", result);
end 
endmodule

Here is the SystemVerilog code

module m ();
 parameter n = 5;
  function int Locate_one (input [n-1:0] a );
    Locate_one = n;
      for (int i =n-1 ; i>=0 ; i=i-1)
      begin
        if(a[i] == 1'b1)
          begin
          Locate_one=i;
            break; 
          end
    end
  endfunction
    logic [n-1:0] a = 3'b111;
    int result;
initial begin 
  result =  Locate_one (a);     
  $display("output is %d ", result);
end 
endmodule

Upvotes: 1

m4j0rt0m
m4j0rt0m

Reputation: 354

I would go with a temp variable inside the function block, indicating if the "1" has been found. It wasn't necessary to initialise the index variable with X's, this should do the work: (I believe this is for simulation purposes as there are no input/output ports)

module first_one ();

  parameter n = 3;
  reg [n-1:0] a;

  function integer locate_one;
    input [n-1:0] a;
    integer i;
    reg found_temp;
    begin
    found_temp = 0;
    for (i=0; i<n; i=i+1) begin
      if(a[i] == 1'b1 & ~found_temp) begin
        locate_one = i;
        found_temp = 1;
      end
    end
    if(~found_temp)
      locate_one = n;
    end
  endfunction

  initial begin
    a = 0;
    $monitor("a = %b : index = %d", a, result);
    #100 $finish;
  end

  wire [$clog2(n)-1:0] result = locate_one(a);

  always
    #1 a = $urandom;

endmodule

This can be tested with icarus verilog:

iverilog first_one.v -o first_one.tb
vvp first_one.tb

Upvotes: 1

Related Questions