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 覆盖。关于如何避免它的方法很少(可能更多)。

  1. 一个明显的,只存放在模拟中实际上是任何未驱动变量的主要输入中。

  2. 在触发器处于非活动状态时在触发器逻辑的输出中放置一个信号。也就是说,如果您在时钟下降时有 @(posedge clk) 存款。

  3. 潜在地,您可以存入任何由这种触发器驱动的信号,除非您有一个组合循环会导致重新评估该信号。

  4. 您还可以根据需要将注射安排在 cbNextSimTimecbNBASynch 等模拟时间事件上。

以上所有内容都适合生成单个模拟事件,该事件将根据它重新评估所有负载。此注入很可能会在接下来的几个模拟周期中被覆盖。

然而,在某些情况下,需要将一个值 force 转化为几个 时钟周期 的信号。在强制事件时立即释放它没有任何意义。这与简单注入的行为方式相同。

您还必须记住,一些模拟器会牺牲强制和注入能力来进行优化。因此,您需要了解在编译中使用哪些限定符 and/or 如何配置您的模拟器以允许强制或注入寄存器 and/or 网络。