Search code examples
verilogsystem-verilog

Use if-generate structure to define two variations of a function, and call that function in the same tb


Here is a small tb, with some example code, where I am trying to define a function two ways, then call that fn below its definition.

module tryfact;
  
  localparam FUNCTION_IS_STATIC = 1;
  
  generate :mygen
    
  if(FUNCTION_IS_STATIC)
      // static fn
      function  integer factorial (input [31:0] operand);
        factorial = 1;
      endfunction: factorial
    
      else
      // automatic fn
      function automatic integer factorial (input [31:0] operand);
        factorial = 1;
      endfunction: factorial
      
  endgenerate :mygen
    
  // test the function
  begin
  integer result;
  initial begin
    result = mygen.factorial(1);
    $display("%0d factorial=%0d", 1, result);
    end
  end
  
endmodule

If I name the block so that it can be called using mygen.factorial1, simulation errors producing:

generate :mygen
           |
xmvlog: *E,UMGENE (testbench.sv,5|11): An 'endgenerate' is expected [12.1.3(IEEE 2001)].
  generate :mygen
           |
xmvlog: *E,EXPENM (testbench.sv,5|11): expecting the keyword 'endmodule' [12.1(IEEE)].
endmodule

If I remove the block label, its fine with the generate, but now I have no hierarchical reference.

xmelab: *E,CUVUNF (./testbench.sv,25|23): Hierarchical name component lookup failed for 'factorial' at 'tryfact'.

How should the generate be named with a single name so that it can be hierarchicaly referenced by that name when called?


Solution

  • This compiles and runs for me without errors on Cadence and Synopsys simulators:

    module tryfact;
      
      localparam FUNCTION_IS_STATIC = 1;
      
      if (FUNCTION_IS_STATIC) begin : mygen
    
          function  integer factorial (input [31:0] operand);
            factorial = 1;
          endfunction: factorial
        
      end else begin : mygen
    
          function automatic integer factorial (input [31:0] operand);
            factorial = 1;
          endfunction: factorial
          
      end
        
      // test the function
      begin
        integer result;
        initial begin
            result = mygen.factorial(1);
            $display("%0d factorial=%0d", 1, result);
        end
      end
      
    endmodule
    

    I added begin/end keywords on each branch of the if/else, and added the mygen label on each branch.

    Refer to IEEE Std 1800-2023, section 27.5 Conditional generate constructs

    I removed the optional generate/endgenerate keywords. I don't think adding a label after the generate keyword is legal syntax.