Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Cross-language Thread Synchronization Between SystemC and SystemVerilog via DPI-C

Tech Jun 11 1

In a mixed-simulation environment where a SystemC reference model must be integrated into a SystemVerilog UVM framework, the SystemC component often runs as a persistent thread rather than a simple request-response module. To achieve this, the simulation must launch concurrent threads in both languages and allow the SystemVerilog side to control a synchronization flag (lock) accessible by the SystemC process.

SystemC Implementation

The SystemC module defines a thread that runs continuously. It uses DPI-C imports to interact with the SV simulation time and check the status of a lock.

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

using namespace std;

extern "C" {
    void advance_time(int cycles);
    bool check_lock_status();
}

SC_MODULE(WorkerModule) {
    SC_CTOR(WorkerModule) {
        SC_THREAD(processing_loop);
    }

    void processing_loop() {
        while (true) {
            cout << "SystemC worker active" << endl;
            advance_time(5);
            
            // Poll lock status with a delay to allow simulation time to progress
            while(check_lock_status()) {
                advance_time(1);
            }
        }
    }
};

extern "C" {

    void log_message(char* msg) {
        printf("SC_Log: %s\n", msg);
    }

    int sc_top(int argc, char* argv[]) {
        WorkerModule worker("worker_inst");
        cout << "SystemC module initialized" << endl;
        sc_start();
        return 0;
    }

    void sc_entry_point(int argc, svOpenArrayHandle argv_handle) {
        char* main_args[argc];
        for (int i = 0; i < argc; i++) {
            char ** ptr = (char **) svGetArrElemPtr(argv_handle, i);
            main_args[i] = *ptr;
        }
        sc_top(argc, main_args); 
    }
}

SystemVerilog Testbench

The SV testbench uses DPI-C to export tasks and functions that the SystemC side can call, effectively creating a shared control mechanism.

module top_tb;
    import "DPI-C" context task sc_entry_point(int argc, string argv[]);  
    import "DPI-C" function void log_message(string msg);

    export "DPI-C" task advance_time;
    export "DPI-C" function check_lock_status;

    bit shared_lock = 1;

    task advance_time(input int cycles);
      repeat(cycles) begin
        #1;
      end
    endtask

    function bit check_lock_status();
      return shared_lock;
    endfunction

    string app_args[5]; 

    initial begin
      app_args[0] = "./sim";
      app_args[1] = "-c";
      app_args[2] = "config.hex";
      app_args[3] = "-m";
      app_args[4] = "fast";

      fork
        begin
          // SV Thread: Toggle lock periodically
          forever begin
            $display("SV Monitor running at time %0t", $time);
            shared_lock = ~shared_lock;
            $display("Lock state changed to %0b", shared_lock);
            #10;
          end
        end
        begin
          // Launch SystemC World
          sc_entry_point(5, app_args);
        end
      join_none
    end
endmodule  

Simulation Output

The output demonstrates that the SystemC thread executes when the lock is released (0) and pauses when the lock is engaged (1), while the SV thread continues to run and toggle the lock.

SV Monitor running at time 378240
Lock state changed to 0
SystemC worker active
SystemC worker active
SV Monitor running at time 378250
Lock state changed to 1
SV Monitor running at time 378260
Lock state changed to 0
SystemC worker active
SystemC worker active
SV Monitor running at time 378270
Lock state changed to 1

A critical issue to avoid is simulation deadlock. If the SystemC polling loop (while(check_lock_status())) does not contain a time-consuming call like advance_time(1), the simulation time will never advance. This prevents the SV thread from executing and releasing the lock, causing both sides to hang. Insreting a delay in the polling loop ensures the simulator yields control back to SV, allowing the lock to be updated.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.