Search code examples
testingverilogverification

Advance time in simulator using Verilog VPI


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?


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.