0

Consider the following function which I would like to parameterize. I have created some parameters to set a width of the input and a corresponding width parameter for the output.

parameter SELECT_WIDTH = 6;
parameter PRIENC_WIDTH = $clog2(SELECT_WIDTH+1);


function [PRIENC_WIDTH-1:0] prienc6;
 input [SELECT_WIDTH-1:0] select;
 reg   [PRIENC_WIDTH-1:0] out;
 begin
   casex(select)
     6'b000001: out = 3'b101;  // Is it possible to parameterize the case statement with generate
     6'b00001x: out = 3'b100;
     6'b0001xx: out = 3'b011; 
     6'b001xxx: out = 3'b010; 
     6'b01xxxx: out = 3'b001; 
     6'b1xxxxx: out = 3'b000; 
   endcase
   prienc6 = out ;
 end
end function

Obviously, the casex statement cases will not expand as written.
So I tried the following, which didn't compile correctly indicating unexpected generate found.

function [PRIENC_WIDTH-1:0] prienc_n;
 input [SELECT_WIDTH-1:0] select;
 reg   [PRIENC_WIDTH-1:0] out;
 begin
   genvar gv_j;
   casex(select)
      for (gv_j = 0; gv_j < SELECT_WIDTH; gv_j = gv_j + 1)
         begin
           {{(SELECT_WIDTH-1)-gv_j{1'b0}},1'b1,{gv_j{1'bx}}} : out = (SELECT_WIDTH-1)-gv_j;
         end
   endcase
   prienc_n = out ;
 end
end function

I have been able to get the correct behavior using parameterized if's, but it seems like I should be able to parameterize that casex statement. Any thoughts on how to do this? I guess what I will try next is to wrap the casex in the generate loop and create 6 casex statements, each with only one state.

1
  • 1
    I recommend using casez instead of casex, because if, in your first example, select became all X's for some reason, that would match any branch because 1'bX means don't care in casex. If you use casez, then select would have to become all Z's for the same thing to happen, which is far less likely to happen. And if you are using System-Verilog, don't use either; use case...inside instead. Commented Sep 15, 2016 at 10:11

1 Answer 1

2

Since you tagged this question with SystemVerilog, I'll show you how to do this without a case statement or generate

function logic [PRIENC_WIDTH-1:0] prienc_n(
 input [SELECT_WIDTH-1:0] select);
 for (int j = 0; j < SELECT_WIDTH; j++) begin
   if (select[SELECT_WIDTH-1]) return j;
   select <<=1;
 end
 // if no 1 found
 return ('x); // you did not specify this case
endfunction

If you need to stay in Verilog, it will need an intermediate variable

   function reg [PRIENC_WIDTH-1:0] prienc_n(
     input [SELECT_WIDTH-1:0] select);
     reg   [PRIENC_WIDTH-1:0] out;
     integer j;
     begin
       out = {PRIENC_WIDTH{1'bx}}; // what should be returned if no 1 found
       for (j = 0; j < SELECT_WIDTH; j = j + 1) begin
         if (select[SELECT_WIDTH-1]) begin 
                                       out = j;
                                       select = 0;
                                     end
         select = select << 1;
     end
     prienc_n = out;
    end
    endfunction
Sign up to request clarification or add additional context in comments.

2 Comments

for the if condition, can we just do if (select[SELECT_WIDTH - 1 - j) return j; which doesn't have to change value of select. for the second function, it looks not right when there are more than one '1' in select.
For the SystemVerilog version, your suggestion works. But after unrolling for synthesis, I think they are they are equivalent. I fixed the second function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.