3

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;
    }
  }
}
vrleboss
  • 463
  • 4
  • 24
  • Do you really need force? can you just put without the force flag? On the other hand it makes absolutely no sense to release as soon as you force. it works the same way as deposit with no force. You need to have a callback on some clock change or other condition to do the release. – Serge Aug 26 '17 at 13:58
  • @Serge. It does in my case. The registers are special radiation hardened regs with asynchronous error correction. I want to test for bit flips in due to radiation. I have tested force with release using the callback triggered by cbForce and it has the behavior I am expecting: registers bits are released immediately after vpiForceFlag - as you can see I am releasing them to the value set by force. But since I am looping over many net each vpiForceFlag trigger all previously set callback functions. So the code is O(n^2) instead of O(n). This is what I would like to fix. – vrleboss Aug 26 '17 at 15:49
  • @Serge To answer your first question: I need the force because in the RTL the registers are continually driven by the code correcting logic. – vrleboss Aug 26 '17 at 15:52
  • But have you tried doing it without force? Your way sounds like it just will create a glitch (if the register value is overwritten in the same data cycle). So is without force/release. There might be some simulator-dependent scheduling attributes which will make them working differently. Usually force means forcing the value to make it stable over a period of time and releasing it after. I afraid that you are exploring a simulator corner case your way. – Serge Aug 26 '17 at 16:19
  • @Serge Very good suggestion, here I thought I would absolutely need to force and release the nets but upon trying your suggestion it is indeed not needed. Maybe the question is of interest for other use cases maybe not. But I'll leave here with our discussion for future reference. If you want to formally post your answer feel free to do so. – vrleboss Aug 26 '17 at 19:08

1 Answers1

1

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.

Serge
  • 11,616
  • 3
  • 18
  • 28