Chapter 11: Advanced Core Semantics

Dynamic Processes (sc_spawn)

How to dynamically create processes at runtime instead of relying solely on static elaboration.

Dynamic Processes (sc_spawn)

Traditionally, SystemC processes (SC_METHOD and SC_THREAD) are static. They are registered during the elaboration phase (in the module's constructor) and exist for the entire duration of the simulation.

But what if you are building an RTOS model and need to dynamically spawn a thread when an interrupt fires? Or what if you want to spawn a watcher thread for every active TLM transaction?

Enter sc_spawn, introduced in IEEE 1666 to provide dynamic process capabilities.

Spawning a Thread

The sc_core::sc_spawn function allows you to create a new process dynamically at runtime. It accepts a callable (usually generated via sc_bind), a string name, and optional spawn configuration options.

Process Handles (sc_process_handle)

When you spawn a process, sc_spawn returns an sc_process_handle. You can use this handle to control the dynamic process:

  • handle.suspend(): Pauses the thread.
  • handle.resume(): Resumes the thread.
  • handle.disable(): Disables sensitivity.
  • handle.kill(): Immediately terminates the thread and throws an sc_unwind_exception.

Complete Dynamic Process Example

Below is a complete, fully compilable sc_main program demonstrating how to dynamically spawn threads, pass arguments to them via sc_bind, configure them as threads or methods, and manage their lifecycle using sc_process_handle.

#include <systemc>
#include <iostream>
#include <vector>
 
// 1. The function we want to spawn dynamically
void my_dynamic_task(int id) {
    try {
        std::cout << "@" << sc_core::sc_time_stamp() << " Task " << id << " started!" << std::endl;
        
        // Consume some simulation time
        sc_core::wait(10, sc_core::SC_NS);
        
        std::cout << "@" << sc_core::sc_time_stamp() << " Task " << id << " finished!" << std::endl;
    } catch (const sc_core::sc_unwind_exception& e) {
        std::cout << "@" << sc_core::sc_time_stamp() << " Task " << id << " was killed!" << std::endl;
        // Optionally re-throw or handle cleanup
    }
}
 
// 2. The module that spawns other processes
class Spawner : public sc_core::sc_module {
public:
    SC_HAS_PROCESS(Spawner);
    
    std::vector<sc_core::sc_process_handle> handles;
 
    Spawner(sc_core::sc_module_name name) : sc_core::sc_module(name) {
        SC_THREAD(run_spawner);
    }
    
    void run_spawner() {
        sc_core::wait(5, sc_core::SC_NS);
        
        std::cout << "Spawner: Creating dynamic threads..." << std::endl;
 
        for (int i = 1; i <= 3; ++i) {
            // Configure the dynamic process
            sc_core::sc_spawn_options opt;
            // E.g., make it a method instead of a thread: opt.spawn_method();
            // opt.dont_initialize();
 
            std::string task_name = "dynamic_task_" + std::to_string(i);
 
            // Spawn a new thread dynamically and store the handle!
            sc_core::sc_process_handle h = sc_core::sc_spawn( 
                sc_core::sc_bind(&my_dynamic_task, i), 
                task_name.c_str(), 
                &opt 
            );
            handles.push_back(h);
        }
 
        // Wait a short time, then kill the second thread prematurely
        sc_core::wait(5, sc_core::SC_NS);
        std::cout << "Spawner: Killing Task 2 prematurely..." << std::endl;
        if (handles.size() >= 2 && handles[1].valid()) {
            handles[1].kill();
        }
    }
};
 
int sc_main(int argc, char* argv[]) {
    Spawner spawner_mod("spawner_mod");
    sc_core::sc_start(30, sc_core::SC_NS);
    return 0;
}

Spawn Options

You can configure the dynamically spawned process using sc_core::sc_spawn_options object passed as the third parameter:

  • spawn_method(): Force the spawned process to be an SC_METHOD instead of a thread. (Note: Methods cannot call wait()).
  • set_sensitivity(): Make the dynamic process sensitive to specific events, just like static processes.
  • dont_initialize(): Prevent the process from running immediately upon creation, meaning it waits for an event in its sensitivity list to trigger it first.

This makes sc_spawn incredibly powerful for modeling complex software stacks, dynamic thread pools in Virtual Platforms, and reactive sequence items in UVM!

Comments and Corrections