LRM Bridge: Core Classes and Process Control
sc_module, sc_module_name, sc_spawn, sc_process_handle, reset, sensitivity, wait, next_trigger, and process control.
The SystemC core classes define how structural models are instantiated and how behavioral processes become schedulable and controllable.
sc_module and sc_module_name
sc_module gives a model its structural hierarchy. The class sc_module_name must be the first parameter in the constructor to support string-based naming during elaboration.
Good module naming is critical. Names appear in reports, traces, hierarchy browsing tools, and are the backbone of CCI and UVM-SystemC hierarchical paths.
Process Macros
The IEEE 1666 standard defines three main process macros:
SC_METHOD: Executes to completion without suspension.SC_THREAD: Runs independently, maintains a stack, and can suspend usingwait().SC_CTHREAD: A specialized thread sensitive to a single clock edge, often used for High-Level Synthesis (HLS).
Complete Process Control & Sensitivity Example
This end-to-end example demonstrates static sensitivity, dynamic sensitivity (next_trigger), reset signaling, and dynamic process control via sc_process_handle.
#include <systemc>
SC_MODULE(ProcessControlDemo) {
sc_core::sc_in<bool> clk;
sc_core::sc_signal<bool> reset{"reset"};
sc_core::sc_event dynamic_event;
// Process handle to control a thread externally
sc_core::sc_process_handle thread_handle;
SC_CTOR(ProcessControlDemo) {
// 1. SC_METHOD with dynamic sensitivity
SC_METHOD(one_shot_method);
dont_initialize();
// 2. SC_THREAD with static sensitivity and asynchronous reset
SC_THREAD(worker_thread);
sensitive << clk.pos();
async_reset_signal_is(reset, true); // Reset is active-high
// Capture the handle of the most recently created process (worker_thread)
thread_handle = sc_core::sc_get_current_process_handle();
// 3. SC_THREAD to control the worker and trigger events
SC_THREAD(controller_thread);
}
void one_shot_method() {
std::cout << "@" << sc_core::sc_time_stamp()
<< " [Method] Fired due to dynamic_event." << std::endl;
// Dynamic sensitivity: trigger again ONLY on the next occurrence
next_trigger(dynamic_event);
}
void worker_thread() {
while(true) {
// Check for reset condition
if (sc_core::sc_process_handle::is_unwinding()) {
std::cout << "@" << sc_core::sc_time_stamp()
<< " [Worker] Thread reset triggered!" << std::endl;
// Perform reset logic here (clear queues, reset state machines)
wait(); // Suspend and wait for reset to clear
}
wait(); // Wait for static sensitivity (clk.pos)
std::cout << "@" << sc_core::sc_time_stamp()
<< " [Worker] Doing work..." << std::endl;
}
}
void controller_thread() {
wait(15, sc_core::SC_NS);
std::cout << "@" << sc_core::sc_time_stamp() << " [Controller] Triggering method." << std::endl;
dynamic_event.notify();
wait(20, sc_core::SC_NS);
std::cout << "@" << sc_core::sc_time_stamp() << " [Controller] Asserting reset." << std::endl;
reset.write(true);
wait(20, sc_core::SC_NS);
std::cout << "@" << sc_core::sc_time_stamp() << " [Controller] De-asserting reset." << std::endl;
reset.write(false);
wait(20, sc_core::SC_NS);
std::cout << "@" << sc_core::sc_time_stamp() << " [Controller] Suspending worker via handle." << std::endl;
thread_handle.suspend();
wait(20, sc_core::SC_NS);
std::cout << "@" << sc_core::sc_time_stamp() << " [Controller] Resuming worker via handle." << std::endl;
thread_handle.resume();
}
};
int sc_main(int argc, char* argv[]) {
sc_core::sc_clock clk("clk", 10, sc_core::SC_NS);
ProcessControlDemo demo("demo");
demo.clk(clk);
sc_core::sc_start(120, sc_core::SC_NS);
return 0;
}Sensitivity
Static sensitivity connects a process to events before simulation starts using sensitive <<.
Dynamic sensitivity is expressed by wait() in threads or next_trigger() in methods.
Use static sensitivity for stable, physical hardware structures (like a clock pin on a D-Flip-Flop). Use dynamic sensitivity when modeling software, TLM state machines, or protocols where the next wakeup event heavily depends on the current runtime state.
Process Handles
sc_process_handle gives programmatic access to a process object. Depending on the simulation phase and process state, a model can suspend(), resume(), disable(), enable(), kill(), or sync with a process.
Use process control carefully. It is extremely powerful but can make models harder to debug if distant modules arbitrarily suspend other blocks' threads.
Reset
SystemC provides standard reset semantics via reset_signal_is (synchronous) and async_reset_signal_is (asynchronous). When a reset is asserted, the kernel gracefully unwinds the process stack, and sc_core::sc_process_handle::is_unwinding() will return true. The process must catch this and return control to the scheduler.
sc_spawn
sc_core::sc_spawn allows dynamic process creation at runtime. While permitted by the LRM, dynamically spawning threads during simulation breaks static elaboration, making debugging and static analysis tools (like structural visualizers) fail. Use sc_spawn predominantly for testbenches and UVM sequence generation, not for hardware RTL modeling.
Comments and Corrections