Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing parameters to a Verilog function

I want to pass a parameter to a function and use it as a parameter (e.g. to select bits) but I don't know how to tell the function that this input is a constant.

For example, if I wanted to do this:

assign foo = bar[MY_PARAM:0];

I want to write my_function so that I could do this:

assign foo = my_function(bar, MY_PARAM);

In my case I need to do a little more that just select bits but not too much, and I'll want it to work for inputs of different bit widths. If I just wanted to select a bit I could use the function below and I'd hope for a solution of similar form but I can't work out the syntax:

function my_function;
  input [3:0] data, my_bit;
  begin
    my_function = data[my_bit];
  end
endfunction

As per Silicon1602's answer, the code I'd need for this would be:

virtual class myClass#(parameter LOCAL_PARAM);
  static function [LOCAL_PARAM:0] my_function;
    input [LOCAL_PARAM:0] data;
    begin
      my_function = data[LOCAL_PARAM:0];
    end
  endfunction
endclass
assign foo = myClass#(MY_PARAM)::my_function(bar);

At first I forgot about the [LOCAL_PARAM] part and was just getting 1-bit back.

like image 514
R.Mckemey Avatar asked Dec 22 '22 21:12

R.Mckemey


2 Answers

The SystemVerilog LRM has a section on your particular case: 13.8 Parameterized tasks and functions. It says:

SystemVerilog provides a way to create parameterized tasks and functions, also known as parameterized subroutines. [...] The way to implement parameterized subroutines is through the use of static methods in parameterized classes (see 8.10 and 8.25).

In your case, you should declare your function like this:

virtual class myClass#(parameter MY_PARAM);
    static function my_function;
        input [MY_PARAM-1:0] data, my_bit;
        begin
            my_function = data[my_bit];
        end
    endfunction
endclass

You could then call your function like this:

assign my_function_output = myClass#(MY_PARAM)::my_function(data, my_bit);

Please note that you may declare multiple functions in your abstract class. So, if you have a whole bunch of functions which all depend on a parameter in the same way, you could all declare them in the same class.


Some additional information on the virtual and static keyword in the aforementioned context:

Section 8.10 of the LRM talks about static methods.

A static method is subject to all the class scoping and access rules, but behaves like a regular subroutine that can be called outside the class, even with no class instantiation. A static method has no access to non-static members (class properties or methods), but it can directly access static class properties or call static methods of the same class.

By using the virtual keyword for the class declaration, you show the compiler that this is an abstract class (see Section 8.21 in the LRM). Creating an object of a virtual class causes a compilation error. This enforces strict static usage of the method.

like image 72
Silicon1602 Avatar answered Dec 29 '22 06:12

Silicon1602


Since the question was also tagged as 'verilog', a similar trick could be played in a simple verilog. You can use parameterized modules to achieve the same effect. For example:

module util#(
  parameter int W = 10)();

  function funct;
    input [W-1:0] inp;
    funct = inp;
  endfunction

endmodule


module top(out, in);
  parameter W = 8;

  output wire [W-1:0] out;
  input wire [W-1:0] in;  

  util#(W) u1(); // inst util module with a parameter
  assign out = u1.funct(in); // call the function

  initial #1 $finish;

endmodule

By default, all functions declared within a module are static.

like image 45
Serge Avatar answered Dec 29 '22 07:12

Serge