Extern function in interface - system-verilog

I am trying to declare a extern function in an interface and implementing it in a separate file in an effort to make our testharness generic.
What i want is something like this:
in_check.sv
interface in_check;
extern function bit fu_check(int num, logic state);
endinterface
in_impl.sv
interface in_impl(in_check uin_check);
function bit uin_check.fu_check(int num, logic state);
if(state) return num;
else return 0;
endfunction
endinterface
But Questasim gives me this error message:
** Error: (vsim-3787) in_impl.sv: Exported function 'uin_check.fu_check' arguments don't match those of export/extern task in interface 'in_check'.
This indicated that it should at least be possible with implicit declaration, but implicitly defined functions (i.e. extern function fu_check) gives this error message:
** Error: (vlog-13069) in_check.sv(20): near "fu_check": syntax error, unexpected IDENTIFIER.
Tasks work perfectly, and I can live with having to use an output argument. However, I would much prefer to be able to give a return value.
How can I make this work?
Bonus question: The LRM seems a bit light in info on this, is the implementation tool specific?

Related

initialize systemverilog (ovm) parameterized class array

I want to monitor several analysis ports, and "publish" the item through one analysis port.
It works for predefined item type, but fail to be parameterized.
The code:
class ovm_analysis_sink #(int NUM_PORTS = 1, type T = ovm_object ) extends ovm_component;
// .......................................
`ovm_component_param_utils(ovm_analysis_sink#(NUM_PORTS,T))
// .......................................
ovm_analysis_imp #(T,ovm_analysis_sink) mon_analysis_imp[NUM_PORTS-1:0];
ovm_analysis_port #(T) mon_analysis_port = new("mon_analysis_port", this);
virtual function void build() ;
string inst;
for(int i=0 ;i < NUM_PORTS ;i++ )
begin
$sformat(inst,"mon_analysis_imp_%0d",i);
mon_analysis_imp[i] = new(inst,this);
end
super.build() ;
endfunction : build
The usage of the analysis_sink:
ovm_analysis_sink #(3,a_type) a_item_sink;
And the error message:
Error-[ICTTFC] Incompatible complex type usage ovm_tb.sv, 42
Incompatible complex type usage in task or function call.
The following expression is incompatible with the formal parameter of the function.
The type of the actual is 'class $unit::ovm_analysis_sink#(3,class $unit::a_type)',
while the type of the formal is 'class $unit::ovm_analysis_sink#(1,class ovm_pkg::ovm_object)'.
Expression: this Source info: ovm_analysis_imp::new(inst, this)
The error says type incompatibility. That means the actual (run-time) and formal (compile-time) arguments/types of implementation port is not the same.
There is an error while declaration of analysis port. Declaring the port as shown above creates a handle of analysis imp port of type uvm_analysis_sink #(1,uvm_object) while, you want it to be of type uvm_analysis_sink #(3,a_type).
So, declare it as follows:
ovm_analysis_imp #(T,ovm_analysis_sink#(NUM_PORTS,T)) mon_analysis_imp[NUM_PORTS-1:0];
This shall remove the type conflict and make it type assignment compatible. Now any parameter overriding shall work.
I have created a sample UVM code on EDAPlayground for reference. Similar applies to your OVM testbench. For further information refer to this forum question.

Updating a classes' variable in a constructor through pass by reference?

Blazing ahead with newfound knowledge of SystemVerilog's inner workings I've set out to use one of these fandangled pass-by-reference features to update a classes' counter in the constructor of another class. The setup (stripped to the basics) looks somewhat like this:
class my_queue;
int unsigned num_items; //Want to track the number of items this Queue has seen.
function push_new_item();
item new_item = new(num_items);
endfunction
endclass
class parent_item;
int unsigned x_th_item;
function new(ref int unsigned num_items);
x_th_item = num_items;
num_items += 1; //This should increase the counter in num_items.
endfunction
endclass
class item extends parent_item;
function new(ref int unsigned num_items);
super.new(num_items);
endfunction
endclass
The issue is that my compiler is complaining about an
Illegal connection to the ref port 'num_items' of function/task parent_item::new, formal argument should have same type as actual argument.
I have an idea on how to fix this: Moving the increment after the call to new() in push_new_items.
But then I still won't know how to correctly use pass-by-refrence in SV so what's causing the error?
Is it the other pass-by-reference or maybe a syntactical error?
You do not need ref semantics for this, use an inout argument.
inout's are copied-in upon entry and copied-out upon return of a task or function. The type compatibility requirements are much stricter as you have seen for ref arguments.
The only occasion you must use a ref argument isin time consuming tasks and you need to see active updates to the arguments before the task returns.
task my_task(ref bit tclock);
#(posedge tclock) // this would hang if tclock was an input
endtask
Another place you might want to use a ref argument is as an optimization when the argument type is a large object like an array. But passing a single int by reference is actually slower than copying its value directly.
Qiu did point me to the issue with my code. My problem was that, whilst the variables were declared correctly on both ends, one of my constructors was written:
function new(ref int num_items);
where it should have rather been
function new(ref int unsigned num_items);
Thank you Qiu.

Systemverilog doesn't allow variable declarations after call to super.foo()?

I'm running into a weird issue working with SystemVerilog on DVT. The code snippet in question looks something like this:
class parent;
int A;
function void foo();
A = 5;
endfunction
endclass
class childA extends parent;
function void foo();
bit test_one; //Does not flag as a syntax error.
super.foo();
bit test_two; //Flags as error: Expected endfunction, found bit.
endfunction //Subsequently: Expected endclass, found endfunction
endclass //And lastly: Unexpected token: Endclass
As far as I know it is legal to call any hidden parent function using super. but this behavior is perplexing me. Can someone tell me if this is legal SV syntax? Or if not: What's the reasoning behind this?
It is illegal syntax. All variables in a task or function must be declared before any operation. See IEEE Std 1800-2012 ยง 13 Tasks and functions (subroutines)
Legal syntax is:
function void foo();
bit test_one;
bit test_two;
super.foo();
endfunction
The only exception is a begin-end block in which case the variable can be declared at the top of the begin-end block before any operation (but you can nest begin-end block). This does however limit scope access and may be less readable. So it not a good practice
function void foo();
bit test_one;
super.foo();
begin
bit test_two; // only in scope within this begin-end
begin
bit test_three; // not the same 'test_three' as below, different scope
end
begin
bit test_three; // not the same 'test_three' as above, different scope
end
// both 'test_three's are out of scope
end
// 'test_two' both 'test_three's are out of scope
endfunction
General best practice is to always declare your variables at the top. I prefer adding empty space between variable declarations and operations a visual separator; makes reading and modifying a ascetically easier.
function void foo();
bit test_one;
bit test_two;
super.foo();
endfunction

Function returning macro?

I'm investigating the Linux kernel where I came across multiple functions that have the following syntax. I'm confused about what this syntax means. I'm not interested what the function does, but what the syntax means.
static int __init customize_machine(void)
{
...
return 0;
}
Here, __init is a macro. It says return 0, so it returns an int, but what is the __init macro doing there?
Also, the macros are found at the end of the function name declaration:
static noinline void __init_refok rest_init(void) __releases(kernel_lock)
{
...
}
Same question: what is the purpose of this macro?
This function is a part of a linux kernel module. The __init macro can be found in linux/module.h. Use it like module_init(customize_machine) and becomes the init function of the module. Returning 0 means the module is loaded successfully.

Timer Thread with passed Function* and Param

I'm working on finishing up my server for my first iPhone application, and I want to implement a simple little feature.
I would like to run a function (perhaps method as well), if another function returns a certain value after a certain waiting period. Fairly simple concept.... right?
Here's my basic foundation.
template <typename T,class TYP>
struct funcpar{
T (*function)(TYP);
TYP parameter;
funcpar(T (*func)(TYP),TYP param);
funcpar& operator=(const funcpar& fp);
};
The goal here is to be able to call funcpar::function(funcpar::parameter) to run the stored function and parameter, and not have to worry about anything else...
When I attempted to use a void* parameter instead of the template, I couldn't copy the memory as an object (because I didn't know what the end object was going to be, or the beginning for that matter) and when I tried multiple timers, every single object's parameter would change to the new parameter passed to the new timer... With the previous struct I have a
question:
Is it possible to make an all-inclusive pointer to this type of object inside a method of a class? Can I templatize a method, and not the whole class? Would it work exactly like a function template?
I have a managing class that holds a vector of these "jobs" and takes care of everything fairly well. I just don't know how to use a templatized function with the struct, or how to utilize templates on a single method in a class..
I'm also utilizing this in my custom simple threadpool, and that's working fairly well, and has the same problems...
I have another question:
Can I possibly store a function with a parameter before it's run? Something like toRun = dontrunmeyet(withThisParameter);? Is my struct even necessary?
Am I going about this whole thing incorrectly?
If this is overly ambiguous, I can set you up with my whole code for context
In order to create a class method that takes a template parameter, yes, it would work almost exactly like a function template. For example:
class A
{
public:
template<typename T>
void my_function(const T& value) { }
};
int main()
{
A test;
test.my_function(5);
return 0;
}
Secondly, for your structure, you can actually turn that into a functor-object that by overloading operator(), lets you call the structure as-if it were a function rather than having to actually call the specific function pointer members inside the structure. For instance, your structure could be re-written to look like this:
#include <iostream>
template <class ReturnType, class ParameterType>
class funcpar
{
private:
ReturnType (*function)(ParameterType);
ParameterType parameter;
public:
funcpar(ReturnType (*func)(ParameterType),ParameterType param):
function(func), parameter(param) {}
funcpar& operator=(const funcpar& fp);
//operator() overloaded to be a function that takes no arguments
//and returns type ReturnType
ReturnType operator() ()
{
return function(parameter);
}
};
int sample_func(int value)
{
return value + 1;
}
int main()
{
funcpar<int, int> test_functor(sample_func, 5);
//you can call any instance of funcpar just like a normal function
std::cout << test_functor() << std::endl;
return 0;
}
BTW, you do need the functor object (or your structure, etc.) in order to bind a dynamic parameter to a function before the function is called in C/C++ ... you can't "store" a parameter with an actual function. Binding a parameter to a function is actually called a closure, and in C/C++, creating a closure requires a structure/class or some type of associated data-structure you can use to bind a function with a specific parameter stored in memory that is used only for a specific instance of that function call.