SystemVerilog VPI 在 vpiForceFlag 之后释放回调句柄
SystemVerilog VPI release a callback handle after a vpiForceFlag
当我问
有人建议我使用 SystemVerilog VPI 代码来解决它。我发布了我的尝试,但意识到在强制净值后我需要释放它。 vpi_put_value(vpi_handle_by_index(net,position),&val,NULL,vpiForceFlag);
我使用由 cbForce
触发的回调函数 release_reg()
来实现。
我的问题是,因为我在许多网络上循环,所以我想在每次回调后释放句柄 cb_handle = vpi_register_cb(&cb_data_s);
。
我的尝试是将回调句柄 cb_handle
传递给回调函数,但它会造成分段错误。
在每个 vpiReleaseFlag
之后 vpi_remove_cb
的正确方法是什么?
这是我的尝试:
#include <sv_vpi_user.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define NULL 0
typedef struct {
vpiHandle net_handle;
vpiHandle cb_handle;
} handle_struct;
//Callback function to relase the vpiForceFlag
int release_reg(p_cb_data cb_data_p) {
vpi_printf ("Releasing bits \n");
handle_struct *hdls;
hdls = (handle_struct *)cb_data_p->user_data;
vpi_put_value(hdls->net_handle,cb_data_p->value,NULL,vpiReleaseFlag);
vpi_remove_cb(hdls->cb_handle); //<- this line causes the pb.
return(0);
}
void reg_flips() {
vpiHandle module_iter;
vpiHandle module_obj;
vpiHandle module_regblk;
vpiHandle reg_nets;
vpiHandle put_handle;
//Starting from the RegBlock
module_regblk = vpi_handle_by_name("DUT.RegBlock",NULL);
//Iterator over all register in RegBlock
module_iter = vpi_iterate(vpiModule,module_regblk);
while (module_iter) {
module_obj = vpi_scan(module_iter);
if (module_obj) {
const char* module_name;
module_name = vpi_get_str(vpiName, module_obj);
reg_nets = vpi_iterate(vpiReg,module_obj); //Iterator over all registers within regblock
while (reg_nets) {
vpiHandle net;
net = vpi_scan(reg_nets);
if (net) {
const char* net_name = vpi_get_str(vpiName, net);
int position = rand()%32; //Position of the bit flip
vpiHandle obj_net;
obj_net = vpi_handle_by_index(net,position); //Getting the net of given position
s_vpi_value val_after; //Value of the net before bit flip
s_vpi_value val_before; //value of the net after bit flip
val_before.format = vpiIntVal;
val_after.format = vpiIntVal;
vpi_get_value(obj_net,&val_before); //Getting the initial value of the net
val_after.value.integer = val_before.value.integer ^ 1; //Flipping the bit
vpi_printf ("Forcing bits in %s - %s[%d] = %d\n",module_name,net_name,position,val_after.value.integer);
//Forcing the value at a given position.
put_handle = vpi_put_value(obj_net,&val_after,NULL,vpiForceFlag);
//Here we define the parameter for the callback function that will release the force statement
vpiHandle cb_handle;
s_cb_data cb_data_s; //Callback object
s_vpi_time time_s; //VPI time object
handle_struct *hdls;
hdls = (handle_struct *)malloc(sizeof(hdls));
hdls->net_handle = obj_net;
hdls->cb_handle = cb_handle;
time_s.type = vpiSimTime; //Simulation time
cb_data_s.reason = cbForce; //Callback is triggered by a force statement
cb_data_s.obj = put_handle; //For cbforce handle of the vpi_put_value needed
//cb_data_s.user_data = malloc(sizeof(hdls));
cb_data_s.user_data = hdls;
cb_data_s.cb_rtn = release_reg; //Function to execute in the callback
cb_data_s.time = &time_s;
cb_data_s.value = &val_after; //Releasing to the same value
cb_handle = vpi_register_cb(&cb_data_s); //PB We need to call vpi_remove_cb on the cb_handle
vpi_release_handle(cb_handle);
}
else {
reg_nets = NULL;
}
}
}
else {
module_iter = NULL;
}
}
}
这里有一些关于如何使用 vpi 在不强制的情况下将值放入(注入)信号的建议。
首先,正如您提到的,大多数信号都可以在仿真周期中由 verilog 重新评估,因此您输入的值有可能被 verilog 覆盖。关于如何避免它的方法很少(可能更多)。
一个明显的,只存放在模拟中实际上是任何未驱动变量的主要输入中。
在触发器处于非活动状态时在触发器逻辑的输出中放置一个信号。也就是说,如果您在时钟下降时有 @(posedge clk)
存款。
潜在地,您可以存入任何由这种触发器驱动的信号,除非您有一个组合循环会导致重新评估该信号。
您还可以根据需要将注射安排在 cbNextSimTime
或 cbNBASynch
等模拟时间事件上。
以上所有内容都适合生成单个模拟事件,该事件将根据它重新评估所有负载。此注入很可能会在接下来的几个模拟周期中被覆盖。
然而,在某些情况下,需要将一个值 force
转化为几个 时钟周期 的信号。在强制事件时立即释放它没有任何意义。这与简单注入的行为方式相同。
您还必须记住,一些模拟器会牺牲强制和注入能力来进行优化。因此,您需要了解在编译中使用哪些限定符 and/or 如何配置您的模拟器以允许强制或注入寄存器 and/or 网络。
当我问 vpi_put_value(vpi_handle_by_index(net,position),&val,NULL,vpiForceFlag);
我使用由 cbForce
触发的回调函数 release_reg()
来实现。
我的问题是,因为我在许多网络上循环,所以我想在每次回调后释放句柄 cb_handle = vpi_register_cb(&cb_data_s);
。
我的尝试是将回调句柄 cb_handle
传递给回调函数,但它会造成分段错误。
在每个 vpiReleaseFlag
之后 vpi_remove_cb
的正确方法是什么?
这是我的尝试:
#include <sv_vpi_user.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define NULL 0
typedef struct {
vpiHandle net_handle;
vpiHandle cb_handle;
} handle_struct;
//Callback function to relase the vpiForceFlag
int release_reg(p_cb_data cb_data_p) {
vpi_printf ("Releasing bits \n");
handle_struct *hdls;
hdls = (handle_struct *)cb_data_p->user_data;
vpi_put_value(hdls->net_handle,cb_data_p->value,NULL,vpiReleaseFlag);
vpi_remove_cb(hdls->cb_handle); //<- this line causes the pb.
return(0);
}
void reg_flips() {
vpiHandle module_iter;
vpiHandle module_obj;
vpiHandle module_regblk;
vpiHandle reg_nets;
vpiHandle put_handle;
//Starting from the RegBlock
module_regblk = vpi_handle_by_name("DUT.RegBlock",NULL);
//Iterator over all register in RegBlock
module_iter = vpi_iterate(vpiModule,module_regblk);
while (module_iter) {
module_obj = vpi_scan(module_iter);
if (module_obj) {
const char* module_name;
module_name = vpi_get_str(vpiName, module_obj);
reg_nets = vpi_iterate(vpiReg,module_obj); //Iterator over all registers within regblock
while (reg_nets) {
vpiHandle net;
net = vpi_scan(reg_nets);
if (net) {
const char* net_name = vpi_get_str(vpiName, net);
int position = rand()%32; //Position of the bit flip
vpiHandle obj_net;
obj_net = vpi_handle_by_index(net,position); //Getting the net of given position
s_vpi_value val_after; //Value of the net before bit flip
s_vpi_value val_before; //value of the net after bit flip
val_before.format = vpiIntVal;
val_after.format = vpiIntVal;
vpi_get_value(obj_net,&val_before); //Getting the initial value of the net
val_after.value.integer = val_before.value.integer ^ 1; //Flipping the bit
vpi_printf ("Forcing bits in %s - %s[%d] = %d\n",module_name,net_name,position,val_after.value.integer);
//Forcing the value at a given position.
put_handle = vpi_put_value(obj_net,&val_after,NULL,vpiForceFlag);
//Here we define the parameter for the callback function that will release the force statement
vpiHandle cb_handle;
s_cb_data cb_data_s; //Callback object
s_vpi_time time_s; //VPI time object
handle_struct *hdls;
hdls = (handle_struct *)malloc(sizeof(hdls));
hdls->net_handle = obj_net;
hdls->cb_handle = cb_handle;
time_s.type = vpiSimTime; //Simulation time
cb_data_s.reason = cbForce; //Callback is triggered by a force statement
cb_data_s.obj = put_handle; //For cbforce handle of the vpi_put_value needed
//cb_data_s.user_data = malloc(sizeof(hdls));
cb_data_s.user_data = hdls;
cb_data_s.cb_rtn = release_reg; //Function to execute in the callback
cb_data_s.time = &time_s;
cb_data_s.value = &val_after; //Releasing to the same value
cb_handle = vpi_register_cb(&cb_data_s); //PB We need to call vpi_remove_cb on the cb_handle
vpi_release_handle(cb_handle);
}
else {
reg_nets = NULL;
}
}
}
else {
module_iter = NULL;
}
}
}
这里有一些关于如何使用 vpi 在不强制的情况下将值放入(注入)信号的建议。
首先,正如您提到的,大多数信号都可以在仿真周期中由 verilog 重新评估,因此您输入的值有可能被 verilog 覆盖。关于如何避免它的方法很少(可能更多)。
一个明显的,只存放在模拟中实际上是任何未驱动变量的主要输入中。
在触发器处于非活动状态时在触发器逻辑的输出中放置一个信号。也就是说,如果您在时钟下降时有
@(posedge clk)
存款。潜在地,您可以存入任何由这种触发器驱动的信号,除非您有一个组合循环会导致重新评估该信号。
您还可以根据需要将注射安排在
cbNextSimTime
或cbNBASynch
等模拟时间事件上。
以上所有内容都适合生成单个模拟事件,该事件将根据它重新评估所有负载。此注入很可能会在接下来的几个模拟周期中被覆盖。
然而,在某些情况下,需要将一个值 force
转化为几个 时钟周期 的信号。在强制事件时立即释放它没有任何意义。这与简单注入的行为方式相同。
您还必须记住,一些模拟器会牺牲强制和注入能力来进行优化。因此,您需要了解在编译中使用哪些限定符 and/or 如何配置您的模拟器以允许强制或注入寄存器 and/or 网络。