一個SystemC執行緒與SystemVerilog執行緒通訊的例子

sasasatori發表於2024-03-13

由於專案需要,現在編寫了一個systemc的reference model要加入到一個systemverilog的uvm框架裡面去。

現在碰到的問題是systemc這邊的model是以執行緒的模式持續執行的,而不是發一個input package給一個output package的模式,因此需要實現:

  1. 整體框架執行在sv中,使用vcs模擬器

  2. 同時拉起一個sc執行緒和一個sv執行緒

  3. sv的執行緒可以控制sc執行緒中的一個鎖的上鎖和解鎖

經過一番實驗後完成的demo如下:

sc程式碼:

#include "systemc.h"
#include "svdpi.h"
#include "svdpi_src.h"
#include <unistd.h>
#include <iostream>

using namespace std;

extern "C" {
    void wait_for_time(int delay_time);
    bool get_lock();
}

SC_MODULE(ThreadExample) {
    SC_CTOR(ThreadExample) {
        SC_THREAD(thread_func);
    }

    void thread_func() {

        while (true) {
            cout << "systemc thread running" << endl;
            wait_for_time(5);
            while(get_lock())
                wait_for_time(1);
        }
    }
};

extern "C" {

    void echo(char* str) {
        printf("%s\n",str);
    }

    int sc_main(int argc, char* argv[]) {
        ThreadExample thread_example("ThreadExample");
        cout << "thread crearted" << endl;
        sc_start();
        return 0;
    }

    void sc_main_wrapper(int argc, svOpenArrayHandle argv) {
        char* argv_main[argc];
        for (int i = 0; i < argc; i++)
        {
            char ** p = (char **) svGetArrElemPtr(argv, i);
            argv_main[i] = *p;
        }
        sc_main(argc, argv_main); 
    }
}

sv程式碼:

// tb.sv
module tb;
    import "DPI-C" context task sc_main_wrapper(int argc, string argv[]);  
    import "DPI-C" function void echo(string str);

    export "DPI-C" task wait_for_time;
    export "DPI-C" function get_lock;

    task wait_for_time(input int delay_time);
      //$display("sc time is",$time);
      repeat(delay_time) begin
        #1;
      end
    endtask

    bit lock = 1;

    function bit get_lock();
      return lock;
    endfunction

    string argv[5]; 

    initial begin
      argv[0] = "./uvm";
      argv[1] = "-f";
      argv[2] = "../../../sw/project/build/rvcim.hex";
      argv[3] = "-R";
      argv[4] = "32";

      fork
        begin
          while (1) begin
            $display("sv thread1 running");
            $display("sv time is",$time);
            lock = ~lock;
            $display("lock is ",lock);
            #10;
          end
        end
        begin
          sc_main_wrapper(5, argv);
        end
      join_none
    end
endmodule  

執行結果(擷取部分):

sv thread1 running
sv time is              378240
lock is 0
systemc thread running
systemc thread running
sv thread1 running
sv time is              378250
lock is 1
sv thread1 running
sv time is              378260
lock is 0
systemc thread running
systemc thread running
sv thread1 running
sv time is              378270
lock is 1
sv thread1 running
sv time is              378280
lock is 0
systemc thread running
systemc thread running
sv thread1 running
sv time is              378290
lock is 1
sv thread1 running
sv time is              378300
lock is 0
systemc thread running
systemc thread running
sv thread1 running
sv time is              378310
lock is 1
sv thread1 running
sv time is              378320
lock is 0
systemc thread running
systemc thread running
sv thread1 running
sv time is              378330

可以看到執行狀態符合預期。

之前碰到的一個問題是,如果在sc執行緒上鎖後等待的while裡面不加延時的話,那麼整個模擬時間無法再前進,從而sv執行緒也無法執行到解鎖,因此sc執行緒無法解鎖也會一直卡死,最後兩個執行緒一起進入死鎖這樣一個狀態。所以透過給while裡面增加一個延時就可以巧妙的解決掉這個問題了。

相關文章