Question

I would like to code a Verilog task using VPI to bit-bang an interface; however, I cannot figure out how to advance simulation time from the VPI task. I am using Mentor Graphics Questa at the moment but also have access to Icarus Verilog. I have successfully forced values on the ports that I am interested in controlling, but the simulation time does not advance, even when a delay is specified on the vpi_put_value.

How is this generally achieved?

Était-ce utile?

La solution

You don't advance simulation time from the VPI (or from an always block, for example) - that would mess with the scheduler. Your VPI code is called in zero sim time; you create new transactions, and tell the scheduler when to act on those transactions. You normally create the new transaction by using parameters 3 and 4 to vpi_put_value (to specify blocking or non-blocking, or some time in the future, for example). This is basically exactly what you do in a process/always block - once you return control, the scheduler works out what to do.

So, in short, use your C code to schedule future (or immediate) transactions, then return, so that the scheduler can work out what to do. You can't put a (simulation) wait in the middle of your C code. I think, in your case, what you want to do is to have a main control loop in the Verilog, with the #10 stuff, and call your C code at the appropriate times.

EDIT

Re your comment: I don't think there's any spec for what vpi_put_delay will do if you attempt to call it multiple times with different delays before returning; it doesn't surprise me that you're seeing only the last delay. Perhaps a little like have multiple NBAs to the same object in an always block; the last one wins. If you really want to schedule multiple transactions on the same object before returning, use vpi_put_delays, with a list of multiple delays (example in Sutherland, p194).

But what's the point? This essentially gives you VHDLs after functionality, with a list of transactions. It doesn't advance simulation time. You're adding all transactions to the event queue at the same time. You can't read the value of any other objects at the 'later' simulation time, because there isn't a later simulation time. See 5.6.4 in the 2005 LRM (not the SystemVerilog LRM; it's a different language). This is like having multiple non-blocking assignments with RHS delays in an always block - all RHS operands are read immediately, without advancing time, but the LHS updates are scheduled for later.

Forget the time advance. You can't do this, because you would mess up everything else on the scheduler queue. What if someone else has scheduled an update in the middle of your time advance? You need to return control to the Verilog code (ie. to the scheduler), so that the scheduler can advance time.

Autres conseils

I know this answer is a bit late but I'm not sure that any of the previous answers addressed your original request though they are not incorrect.

You cannot call vpi_put_value on the same handle multiple times in one simulation step to queue values in time. Only the final call will have any effect.

What you want to do is call vpi_put_value to force the value you want now and then register a callback using the cbAfterDelay for the next time you want to change the value. When your callback handler executes simulation time will have advanced to that point and thus you can force the next value onto the handle.

Your callback function would do something like this:

static int32_t handle_vpi_callback(p_cb_data cb_data) {
    // advance your driver state using user_data to retrieve current state
    // call vpi_put_value with new signal value
    // determine next time value requiring action
    // register another callback
}

And to register the timed callback:

s_cb_data cb_data_s;
s_vpi_time vpi_time_s;
p_vpi_cb_user_data user_data;

vpi_time_s.type = vpiSimTime;
vpi_time_s.high = (uint32_t)(time_ps>>32);
vpi_time_s.low  = (uint32_t)(time_ps);

cb_data_s.reason    = cbAfterDelay;
cb_data_s.cb_rtn    = handle_vpi_callback;
cb_data_s.obj       = NULL;
cb_data_s.time      = &vpi_time_s;
cb_data_s.value     = NULL;
cb_data_s.user_data = (char *)user_data;

vpiHandle new_hdl = vpi_register_cb(&cb_data_s);

This will be equivalent in behaviour to the Verilog code:

#10 value = something;
#5  value = something_else;

If your bus is synchronous to a clock you may want to drive only the clock using a cbAfterDelay (or drive it from a process in Verilog) and advance your driver state registering a cbValueChange on the clock itself. This will mimic a clocked process running in the simulator.

If you're familiar with Python you may be interested in an open-source project called Cocotb which abstracts VPI to provide a nice Pythonic interface to you Device Under Test (DUT) running in the simulator. If you have existing C++ code that you want to interface then going via Python might save you some time.

For example to send a buffer over an interface your driver send routine might look like this:

def send(dut, buffer):
    """Send a buffer over a packetised bus"""

    bus_width = len(dut.data) / 8
    firstword = True

    while buffer:
        yield RisingEdge(dut.clk)

        nbytes = min(len(buffer), bus_width)
        dut.data.value = buffer[:nbytes]
        dut.valid.value = 1
        dut.startofpacket.value = int(firstword)

        if nbytes <= buswidth:
            dut.endofpacket.value = 1
            dut.empty.value = bus_width - len(buffer)
            buffer = ""
        else:
            buffer = buffer[buswidth:]

        firstword = False

    yield RisingEdge(dut.clk)
    dut.valid.value = 0
    dut.endofpacket.value = 0

Disclaimer: I'm one of the Cocotb developers.

I was unable to find any direct examples. I was able to find a several places in the LRM that refer to "Simulation time" relating to VPI. Accoding to the LRM it is possible; IEEE Std 1800-2012 section 36.9.2 in paragraph 2 states:

"The VPI simulation callback facility shall provide the application with the means to interact dynamically with a tool, detecting the occurrence of value changes, advancement of time, end of simulation, etc."

Here are other places time is mention as VPI:

  • 37.79 Time Queue
  • 38.10 vpi_get_delay()
  • 38.13 vpi_get_time()
  • 38.32 vpi_put_delay()
  • 38.34 vpi_put_value() has a time_p component
  • 38.36 vip_register_cb()
    • 38.36.1.1 mentions vpiSimTime and vpiSuppressTime
    • 38.36.2 Simulation time callbacks

If all else fails, try SystemC (IEEE Std 1666-2011) instead. Tutorial at http://www.asic-world.com/systemc/systemc_time.html and a direct example on part 3.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top