Search code examples
csystem-verilogvpi

SystemVerilog VPI release a callback handle after a vpiForceFlag


When I asked SystemVerilog looping through hierarchy I was suggested to use a SystemVerilog VPI code to solve it. I posted my attempt but realized that after forcing the net value I need to release it. vpi_put_value(vpi_handle_by_index(net,position),&val,NULL,vpiForceFlag);

I do it using a callback function release_reg() triggered by cbForce.

My issue is that because I am looping over many nets I would like to release the handles cb_handle = vpi_register_cb(&cb_data_s); after each callback.

My attempt was to pass the callback handle cb_handle to the callback function but it creates a segmentation fault.

What would be the proper way to vpi_remove_cb after each vpiReleaseFlag ?

Here is my attempt:

#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;
    }
  }
}

Solution

  • Here are a few suggestions on how to put (inject) a value into a signal without forcing, using vpi.

    First of a all, as you mentioned, most of the signals can be re-evaluated by verilog during the simulation cycle, therefore there is a chance that the value you put would be overwritten by verilog. There are few ways on how to avoid it which com to mind (could be more).

    1. an obvious one, only deposit in primary inputs which are actually any undriven variable in the simulation.

    2. deposit a signal in the output of a flop logic at the time when the flop is inactive. i.e. if you have a @(posedge clk) deposit at clock change when it goes down.

    3. potentially, you can deposit into any signal driven by such flop, unless you have a combinatorial loop which will cause re-evaluation of this signal.

    4. you can also schedule your injections on the simulation time events like cbNextSimTime or cbNBASynch or others, depending on your needs.

    All the above is good to generate a single simulation event which would re-evaluate all loads depending on it. Most likely this injection will be overwritten in the next few simulation cycles.

    In some cases however it is needed to force a value into a signal for several clock cycles. It does not make any sense to release it immediately at the force event. This behaves the same way as a simple injection.

    Also you have to remember that some simulators sacrifice forcing and injection ability for optimization. So, you need to understand which qualifiers to use in compilation and/or how to configure your simulator to allow forcing or injecting registers and/or nets.