Below code throws error when simulation is loaded, if right-hand side of cast operation is not given as class type.
I would like it to work with types of class or other data types such as struct. When given type is struct, cast statement gives error saying arguments should be singular types. How can I make this code to work with both types?
$cast can only be used on singular data types. The LRM provides the following definition:
singular: An expression, data object, or data type that represents a single value, symbol, or handle. A singular data type is any data type except an unpacked structure, unpacked union, or unpacked array data type.
Without knowing exactly what you are trying to accomplish, it’s difficult to provide an answer.
When you instantiate param_class, you should know the two types that you are using as parameters. You could have two different functions, one that uses $cast and one that uses assignments, and use the appropriate version.
class param_class #(type type_foo = some_def_type,
type type_bar = some_def_type,
bit is_singular = 1);
type_foo foo;
type_bar bar;
function void some_func_singular();
$cast(foo, bar);
endfunction
function void some_func_non_singular();
foo = bar;
endfunction
function void some_func();
if (is_singular) some_func_singular();
else some_func_non_singular();
endfunction
endclass
Actually that won’t work because the function need to pass compilation even if they are never used. But you can achieve something similar by using what called a strategy or policy design pattern. It essentially works by wrapping functionality in an object specific to the types you need.
module top;
typedef struct {int A;} some_def_type;
class A;
endclass
interface class policies #(type from_type, to_type);
pure virtual function void copy(input from_type from, output to_type to);
pure virtual function logic compare(input from_type lhs, output to_type rhs);
endclass
class policy_struct#(type from_type, to_type) implements policies#(from_type,to_type);
virtual function void copy(input from_type from, output to_type to);
to = to_type'(from);
endfunction
virtual function logic compare(input from_type lhs, output to_type rhs);
return lhs == to_type'(rhs);
endfunction
endclass
class policy_class#(type from_type, to_type) implements policies#(from_type,to_type);
virtual function void copy(input from_type from, output to_type to);
$cast(to,from);
endfunction
virtual function logic compare(input from_type lhs, output to_type rhs);
return 0; // did not implement yet
endfunction
endclass
class param_class #(type type_foo = some_def_type,
type type_bar = some_def_type);
type_foo foo;
type_bar bar;
policies#(type_foo,type_bar) policy;
function void some_func();
policy.copy(bar,foo);
endfunction
endclass
param_class#(some_def_type,some_def_type) h1 = new;
policy_struct#(some_def_type,some_def_type) h2 = new;
initial begin
h1.policy=h2;
h1.some_func;
end
endmodule
You should use in interface class anywhere you have a abstract/virtual class with only pure virtual methods. An interface class gives you access to multiple inheritance. A single class can implement multiple interface classes as well as be extended from another base class.
You can break up your policies into individual interface classes and then group them together as needed. For example suppose you had policies for create, compare, copy, and clone (create followed by copy). A class policy might implement all 4 policies, but a struct policy would only implement copy and compare. As you define more policies for a broader range of types, the end user class only needs to declare interface class variables for policies that it needs, and will only work with types that have defined the policies it needs. The paper goes into this in more detail.