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.)
01 | import numpy as np |
02 | import matplotlib.pyplot as plt |
03 | import matplotlib.animation as animation |
04 |
05 | def data_gen(): |
06 | t = data_gen.t |
07 | cnt = 0 |
08 | while cnt < 500 : |
09 | cnt + = 1 |
10 | t + = 0.05 |
11 | yield t, np.sin( 2 * np.pi * t) * np.exp( - t / 10. ) |
12 | data_gen.t = 0 |
13 |
14 | fig = plt.figure() |
15 | ax = fig.add_subplot( 111 ) |
16 | line, = ax.plot([], [], lw = 2 ) |
17 | ax.set_ylim( - 1.1 , 1.1 ) |
18 | ax.set_xlim( 0 , 5 ) |
19 | ax.grid() |
20 | xdata, ydata = [], [] |
21 | def run(data): |
22 | # update the data |
23 | t,y = data |
24 | xdata.append(t) |
25 | ydata.append(y) |
26 | xmin, xmax = ax.get_xlim() |
27 |
28 | if t > = xmax: |
29 | ax.set_xlim(xmin, 2 * xmax) |
30 | ax.figure.canvas.draw() |
31 | line.set_data(xdata, ydata) |
32 |
33 | return line, |
34 |
35 | ani = animation.FuncAnimation(fig, run, data_gen, blit = True , interval = 10 , |
36 | repeat = False ) |
37 | 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.
01 | #include <windows.h> |
02 | #include <vpi_user.h> |
03 | #include <svdpi.h> |
04 | #include <cassert> |
05 | #include <iostream> |
06 | #include "..\source\dpi_veritak_header.h" |
07 |
08 |
09 | extern "C" __declspec ( dllexport ) int process_run() //task |
10 | { |
11 | STARTUPINFO si; |
12 | PROCESS_INFORMATION pi; |
13 | const char command[]= "C:\\Python33\\python decade.py" ; |
14 | |
15 | //Run Python animation |
16 | bool success=CreateProcess(NULL, ( LPSTR )command, NULL, NULL, TRUE, 0, NULL, NULL, &si, π); |
17 | if (success){ |
18 | WaitForInputIdle(pi.hProcess, INFINITE); |
19 | while (1){ |
20 | DWORD status=WaitForSingleObject(pi.hProcess, 0); // |
21 | if (status==WAIT_TIMEOUT){ //If process still exists |
22 | delay(1000); //We will be alive after 1000clks |
23 |
24 | |
25 | } else { |
26 | //If the process exits, we also exit. |
27 | CloseHandle(pi.hThread); |
28 | CloseHandle(pi.hProcess); |
29 | return 0; |
30 | } |
31 | } |
32 | |
33 | } |
34 | return 0; |
35 | }</iostream></cassert></svdpi.h></vpi_user.h></windows.h> |
In SystemVerilog source,we make 4 threads. If any of thread finishes, then
we'll exit.
01 | program hello_dpi_world; |
02 |
03 | |
04 | import "DPI-C" context task process_run(); |
05 | export "DPI-C" task delay; |
06 |
07 | bit clk=0; |
08 | int counter=0; |
09 |
10 |
11 | task delay( longint rep1) ; |
12 | repeat (rep1) begin |
13 | @( negedge clk); |
14 | end |
15 | endtask |
16 |
17 | |
18 |
19 | initial |
20 | fork //4 threads run in parallel |
21 | forever #10 clk=~clk; |
22 | forever @( posedge clk) counter<=counter+1; |
23 | process_run(); |
24 | wait (counter==20000000); |
25 | join_any |
26 | //Finished! |
27 | |
28 |
29 |
30 | endprogram |