initialize systemverilog (ovm) parameterized class array - system-verilog

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.

Related

How to create a newtype operation in Q#?

I am working with Q# on a generic grover search implementation and I wanted to define a custom Oracle type
newtype ModelOracle = ((Qubit[], Qubit[], Int[], Qubit) => Unit);
// ...
function GroverMaxMatchingOracle(search_set: (Int,Int)[], vertices: Int[], marked_pts: Bool[]): ModelOracle {
return ModelOracle(ApplyMaxMatchingOracle(_,_,_,_,search_set, vertices, marked_pts));
}
that will fit into my model. But when I try to use it (kind of in the same way as they use StateOracle in the DatabaseSearch sample), I get an error saying that the new type ModelOracle is not a valid operation
fail: Microsoft.Quantum.IQSharp.Workspace[0]
QS5021: The type of the expression must be a function or operation type. The given expression is of type OracleHelper.ModelOracle.
What am I getting wrong about the types here?
It looks like you have defined things ok, so it might be that you have to unwrap the user defined type first with the ! operator.
So where you are using it you may have to do something like GroverMaxMatchingOracle!(...)
Another approach could be to name the tuple in your UDT:
newtype ModelOracle = (Apply: (Qubit[], Qubit[], Int[], Qubit) => Unit);
Then wherever you want to use it you can directly used the named item Apply like this: GroverMaxMatchingOracle::Apply(...)
If its helpful, there is a section on user defined types (8.2) in the book #cgranade and I are working on, Learn Quantum Computing with Python and Q#

Can you either, forward declare a type to be used as a port type or can you use an interface as an external port?

I'm trying to design some hardware in SystemVerilog and I've run into a problem I can't find the answer to. The situation is that I have a top level module (tracer), which needs to have an output port of a particular type. This type is a typedefed struct which is specified inside an parameterised interface, as this type definition needs to be shared among some of the submodules of the top level module. I want to be able to have an output port that is of a type specified in the interface and to be able to pass that type into various submodules for other purposes.
Crucially I'm also trying to make this hardware as a piece of Custom IP in Vivado (this is one part of a larger project) so I'm aiming for a top-level module where there are some parameters I can define and the rest of the module is fully encapsulated. I realise this will involve placing a Verilog wrapper on top of everything in the end but at the moment I'm just focussing on getting it to run in simulation correctly.
The problem I've had is that because interfaces have to be instantiated you can't use one as a top-level port because where would you instantiate the interface? However because all I'm doing is referring to typedefs inside the interface surely I can forward declare these somehow so that I can refer to the type as a port type and pass it into other submodules?
So essentially does anyone have any idea as to how I might achieve this? If I'm going about this entirely incorrectly then feel free to tell me, the idea of bundling up the typedefs into an interface was provided by dave59 here (https://verificationacademy.com/forums/systemverilog/parameterized-struct-systemverilog-design), and I've spent a day trying to solve this and have got nowhere. Any help gratefully appreciated and any further clarifications I'll happily provide.
Here is the code for each as it currently stands. These are both declared in the same file just for clarity.
Interface Definition
interface trace_if #(
parameter TDATA_WIDTH = 32,
parameter INSTR_ADDR_WIDTH = 32,
parameter INSTR_DATA_WIDTH = 32,
parameter DATA_ADDR_WIDTH = 32);
... (IF_DATA etc. defined here)
typedef struct packed {
bit [INSTR_DATA_WIDTH-1:0] instruction;
bit [INSTR_ADDR_WIDTH-1:0] addr;
bit pass_through;
IF_data if_data;
ID_data id_data;
EX_data ex_data;
WB_data wb_data;
} trace_format;
trace_format trace_output;
endinterface
Top-Level Module
module tracer
#(
parameter INSTR_ADDR_WIDTH = 32,
parameter INSTR_DATA_WIDTH = 32,
parameter DATA_ADDR_WIDTH = 32,
parameter TDATA_WIDTH = 32,
parameter TRACE_BUFFER_SIZE = 64
)
(
... other ports declared
trace_if.trace_output trace_data_o
);
// Instantiating the interfaces for communication between submodules
logic if_data_valid;
trace_if #(TDATA_WIDTH, INSTR_ADDR_WIDTH, INSTR_DATA_WIDTH, DATA_ADDR_WIDTH) if_data_o();
logic id_data_ready;
trace_if #(TDATA_WIDTH, INSTR_ADDR_WIDTH, INSTR_DATA_WIDTH, DATA_ADDR_WIDTH) id_data_o();
logic ex_data_ready;
trace_if #(TDATA_WIDTH, INSTR_ADDR_WIDTH, INSTR_DATA_WIDTH, DATA_ADDR_WIDTH) ex_data_o();
logic wb_data_ready;
// Instantiating the submodules
if_tracker if_tr (.*);
id_tracker #(INSTR_DATA_WIDTH, DATA_ADDR_WIDTH, TRACE_BUFFER_SIZE) id_tr(.if_data_i(if_data_o), .*);
ex_tracker #(DATA_ADDR_WIDTH, 256, TRACE_BUFFER_SIZE) ex_tr(.id_data_i(id_data_o), .wb_previous_end_i(previous_end_o), .*);
wb_tracker #(TRACE_BUFFER_SIZE) wb_tr(.ex_data_i(ex_data_o), .wb_data_o(trace_data_o), .*);
... other module related stuff
endmodule
These things are easier if you publish an MCVE. I think what you are asking is this:
interface i #(parameter p = 1);
typedef struct packed {
bit [p-1:0] b;
} s_t;
s_t s;
endinterface
module m #(parameter p = 1) ( /* how can I have a port of type s_t ? */ );
i i0 ();
endmodule
If so, I think you need to put your struct in a package:
package pkg;
localparam l = 1;
typedef struct packed {
bit [l-1:0] b;
} s_t;
endpackage
interface i #(parameter p = pkg::l);
pkg::s_t s;
endinterface
module m #(parameter p = pkg::l) ( pkg::s_t s );
i i0 ();
endmodule
https://www.edaplayground.com/x/4zQ_

Extern function in interface

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?

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.

Why does asObject allow use of SimpleLongProperty with setCellValueProperty?

I am using setCellValueFactory to configure my TableView column using a lambda expression. The underlying property is a SimpleLongProperty. I have found that the lambda expression
ageColumn.setCellValueFactory(cellData -> cellData.getValue().ageProperty());
does not work if ageProperty is a SimpleLongProperty.
I have found the solution to this problem is to add the asObject method as follows:
ageColumn.setCellValueFactory(cellData -> cellData.getValue().ageProperty().asObject());
It is not clear to me why adding the asObject method causes the lambda to return the right type of an ObservableValue. I understand it has something to do with the fact that SimpleLongProperty implements ObservableValue(Number)rather than ObservableValue(Long) but I can't see why this matters. In any case, how does asObject() fix this problem?
This is basically just a type matching issue.
TableColumn<S, T> defines a method setCellValueFactory(Callback<CellDataFeatures<S,T>, ObservableValue<T>> factory).
Since you have defined the column as a TableColumn<Configuration, Long>, its setCellValueFactory is expecting a Callback<CellDataFeatures<Configuration, Long>, ObservableValue<Long>> as the parameter; i.e. it is expecting something that defines a method
public ObservableValue<Long> call(CellDataFeatures<Configuration, Long> cellDataFeatures) ;
If you pass this as a lambda expression of the form
cellData -> <some expression>
then the compiler will infer that cellData is a CellDataFeatures<Configuration, Long> and will require that the expression evaluates to an ObservableValue<Long>.
So cellData.getValue() will evaluate to a Configuration, and if you define the age property in Configuration as a LongProperty, then of course cellData.getValue().ageProperty() evaluates to a LongProperty. This causes a type mismatch and the compiler complains. Remember that the compiler is expecting this expression to evaluate to an ObservableValue<Long>; as you observed LongProperty implements ObservableValue<Number>, not ObservableValue<Long>. Thus your expression evaluates to an ObservableValue<Number> instead of the required type of ObservableValue<Long>.
Both the fixes you mentioned work: changing the column to a TableColumn<Configuration, Number> works because the compiler is then expecting a lambda expression evaluating to an ObservableValue<Number> (which it is getting).
Calling asObject() on the LongProperty works too. As the Javadocs state, this method creates an ObjectProperty<Long> that is bidirectionally bound to the LongProperty. Since ObjectProperty<T> implements ObservableValue<T>, cellData.getValue().ageProperty().asObject() is an ObservableValue<Long> as required.