0
votes

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
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. - Matthew Taylor

1 Answers

2
votes

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