4.9 Export ( Direct Programming Interface)

4.9.9 Running Another process in parallel

With power of SystemVerilog DPI task, we can run both simulation and another process in parallel, polling status of the invoked process. Video capture is here.
Below is an example process from gallery of matplotlib. ( You need additional installations, numpy and matplotlib as python library for run.)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

def data_gen():
    t = data_gen.t
    cnt = 0
    while cnt < 500:
        cnt+=1
        t += 0.05
        yield t, np.sin(2*np.pi*t) * np.exp(-t/10.)
data_gen.t = 0

fig = plt.figure()
ax = fig.add_subplot(111)
line, = ax.plot([], [], lw=2)
ax.set_ylim(-1.1, 1.1)
ax.set_xlim(0, 5)
ax.grid()
xdata, ydata = [], []
def run(data):
    # update the data
    t,y = data
    xdata.append(t)
    ydata.append(y)
    xmin, xmax = ax.get_xlim()

    if t >= xmax:
        ax.set_xlim(xmin, 2*xmax)
        ax.figure.canvas.draw()
    line.set_data(xdata, ydata)

    return line,

ani = animation.FuncAnimation(fig, run, data_gen, blit=True, interval=10,
    repeat=False)
plt.show()


We invoke this process (animation) by C as imported task in SystemVerilog per following cpp source.Please note this is real multi-process, not quasi-mulltithread.
Generally speaking, simulator engine is single process, and DPI is not thread-safe for multiple threads. However you can invoke multiple process or threads if you take care of your own threads.

Important point is to pass the control to simulation kernel by calling exported task , "delay".
With the task,we can poll status of invoked process every 1000 clks.

#include 
#include 
#include 
#include 
#include 
#include "..\source\dpi_veritak_header.h"


extern "C"  __declspec(dllexport) int process_run() //task 
{       
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        const char command[]="C:\\Python33\\python decade.py";
        
        //Run Python animation
        bool success=CreateProcess(NULL, (LPSTR)command, NULL, NULL, TRUE, 0, NULL, NULL, &si, π);
        if (success){
                WaitForInputIdle(pi.hProcess, INFINITE);
                while (1){
                        DWORD status=WaitForSingleObject(pi.hProcess, 0);//
                        if (status==WAIT_TIMEOUT){//If process still exists
                                delay(1000);//We will be alive after 1000clks

                                
                        }else {
                                //If the process exits, we also exit.
                                CloseHandle(pi.hThread);
                                CloseHandle(pi.hProcess);
                                return 0;
                        }
                }
                
        }
        return 0;
}


In SystemVerilog source,we make 4 threads. If any of thread finishes, then we'll exit.

program hello_dpi_world;

        
        import "DPI-C" context task process_run();
        export "DPI-C" task delay;

        bit clk=0;
        int counter=0;


        task delay(longint rep1) ;
                repeat(rep1) begin
                        @(negedge clk);
                end
        endtask

        

        initial 
                fork //4 threads run in parallel
                        forever #10                     clk=~clk;
                        forever @(posedge clk) counter<=counter+1;
                        process_run();
                        wait (counter==20000000);
                join_any
                //Finished!
        


endprogram