Vladimir Maletic
VPI Integration of ErrorAnalyzer using Icarus Verilog
Aktualisiert: 27. Mai 2021
A step into ErrorAnalyzer integration
In order to ease the life of the verification engineers by helping them to analyze and understand failing simulation faster, we have developed ErrorAnalyzer - productivity EDA tool for failing simulation. It helps by reducing the debugging effort and providing the verification engineer with detailed information about failing signals as well as proposing error patterns represented in textual and graphical form. However, ErrorAnalyzer has to be previously integrated into existing verification environments in order to do its job. The integration is done by using both VPI and DPI interfaces. In this case we are going to see how the integration of our product was implemented using Verilog Procedural Interface - VPI. The chosen simulator is Icarus Verilog, a Verilog simulation and synthesis tool, which provides very decent VPI support.
Let's first go a bit through the background of the VPI…
The Verilog Procedural Interface, originally known as PLI 2.0, is an interface primarily intended for the C programming language. It allows behavioral Verilog code to invoke C functions, and C functions to invoke standard Verilog system tasks and functions. The VPI is part of the IEEE 1364 Programming Language Interface standard. (1) The fact that all the functions and tasks start with vpi_* makes VPI is cleaner than its predecessor PLI 2.0. When it comes to difference between DPI and VPI approach, both have their advantages. Main advantage of using DPI is speed. On the other hand, VPI eases debugging on development, making user capable of accessing simulation data structures from "outside" the simulation module. In other words, user can freely access, read and change the signals in the simulation.

Figure 1: Example on accessing vpiHandle (signal) by name
But how the simulator recognizes and imports ErrorAnalyzer API?
The answer is simple. ErrorAnalyzer shared library is provided to the list of VPI modules which are immediately loaded by the simulator. Therefore, simulator recognizes one-to-one function calls from the simulation interface. Some of the ErrorAnalyzer API is provided as one-to-one functions while some are registered as callback functions. Callback functions are the functions which would be called on the specific event in the simulation. An example of registered callback is shown in the figure below.

Figure 2: Callback registration
In fact, the function eaSimEndCb() is called, as stated in the callback, at the end of the simulation, which is the reason of the callback. Another possible reason we are using is cbValueChange, which is used when adding samples to the previously created Analyzer. The systems tasks can also be registered as one-to-one functions, like in code snippet represented in the Figure 3.

Figure 3: Registration of system function
Meaning of the code snippet above is following: function eaVPIAnalyzerCreate() is called when simulator module invokes function call $eaVPIAnalyzerCreate. The arguments of the invoked functions are checked by the user defined function eaVPIAnalyzerCreateCompiletf(). If any argument is invalid or missing, simulation would simply stop the execution.
Finally, function calls should be provided to the simulator, in order to recognize their calls. It is done in the normal way shown in the Figure 4, where all user defined C functions are associated with a new system task and referred in Verilog. Associated system functions have one common task – call the appropriate functions from ErrorAnalyzer API and provide them with corresponding parameters.

Figure 4: Registering new system tasks
After carefully preparing all above mentioned VPI integration requirements, our simulator is richer for eight new system tasks from ErrorAnalyzer API, making our product capable of reaching the most inapproachable signal in the whole simulation process.
(1) https://en.wikipedia.org/wiki/Verilog_Procedural_Interface